home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / prgmming / qb_tips / qbtips_j.doc next >
Text File  |  1993-04-09  |  222KB  |  5,896 lines

  1.  
  2.  
  3. Name:             QBTips_J.Doc                         Date:  6/93
  4.  
  5. Also See:         QBTips_A through QBTips_I
  6.  
  7.  
  8. Purpose:          To provide insights and source code to help BASIC
  9.                   programmers -- beginner through advanced.
  10.  
  11.                   Load this into your word processor or editor.  Then
  12.                   scan it for tidbits you think will be useful.  Just
  13.                   "cut & paste" sections you like to separate files,
  14.                   then run the code.
  15.  
  16.  
  17. Source:           Below you'll find messages captured from the FidoNet
  18.                   Quik_Bas echo.  We captured CODE and significant tips,
  19.                   and eliminated chatter.
  20.  
  21.  
  22. Format:           Varies, depending on the author, their programming
  23.                   style, and the question or topic.
  24.  
  25.                   A form-feed (Chr$(12)) appears after most messages.
  26.                   This allows you to print this, and have each message
  27.                   (ie., each topic) start on a new page.
  28.  
  29.  
  30. Recommendation:   None!
  31.  
  32.                   Some of what you'll see below is brilliant.  Some
  33.                   demonstrates very poor programming techniques.  But
  34.                   all of it can prove useful if you have a need.
  35.  
  36.                   NOTE 1:
  37.  
  38.                   We have NOT tried all the code you see here, and some
  39.                   of it may not run as-is.  You may have to do a little
  40.                   editing to coax it.  One reason that code may not run
  41.                   is that messages sometimes get truncated or mangled in
  42.                   transmission.  Another reason is that authors make
  43.                   mistakes (or typos).  Again, we haven't tried running
  44.                   everything; but when you do, you'll probably quickly
  45.                   spot places that need editing.
  46.  
  47.                   NOTE 2:
  48.  
  49.                   There may be near-duplicate messages.  The original
  50.                   author may have refined the code, or may have found
  51.                   errors in the original.  If you see something that
  52.                   looks interesting, before you rely on the code, scan
  53.                   for the topic or author to see if a new set of code is
  54.                   below you -- more recent messages appear below. And
  55.                   note that the next message may be in a later package.
  56.  
  57.                   NOTE 3:
  58.  
  59.                   BEFORE running any code segment, scan through it and
  60.                   LOOK FOR code fragments which could be DISASTROUS!
  61.  
  62.                   *** We often run un-tested code fragments from a  ***
  63.                   *** RAM or floppy disk.  And BEFORE running it we ***
  64.                   *** scan for "c:" or "d:" (or other hard drive)   ***
  65.                   *** letters.  And we also scan for .. (see below) ***
  66.  
  67.  
  68.                   For example, scan for "OUT " -- and if you find any
  69.                   verify that the code is OUTting the correct values
  70.                   to the correct ports.  Typos, transmission errors
  71.                   or programmer mistakes could send the wrong values
  72.                   to the wrong ports.  At best, nothing will happen.
  73.                   At worst, you might fry your monitor -- or worse.
  74.  
  75.                   Also look for INTERRUPT (or INTERRUPTx).  These functions
  76.                   are v-e-r-y useful for invoking low-level DOS or BIOS
  77.                   functions.  But that low-level access also comes with
  78.                   some risks!  Programmer or transmission errors, open
  79.                   drive doors, etc., can, at best, cause your PC to hang.
  80.                   At worst, you could corrupt the FAT of your hard disk.
  81.  
  82.  
  83. =========================================================================
  84.  
  85.  
  86.  
  87.  
  88. Msg #:  8690                      QUIKBAS Subboard
  89.  From:  EARL MONTGOMERY           Sent: 03-27-93 19:40
  90.    To:  ALL                       Rcvd: -NO-
  91.    Re:  HEX-BIN.DOC
  92.  
  93.  
  94. While refreshing my memory on Hexadecimal and Binary notations
  95. (and the use of the logical operators <AND> <OR>, I found that
  96. it helped to take notes. This is a compilation of those notes.
  97. Some phrasing is entirely my own. So if you find any mistakes
  98. (other than grammar, sentence structure, or spelling! <smile>)
  99. please inform me so I can correct my document file. This
  100. document should prove useful to the new programmers.
  101.  
  102.                      A little info on Hexadecimal notation.
  103.  
  104. Hexadecimal is a numbering system based on 16 elements.
  105. Digits are numbered 0 through F as follows:
  106.  
  107. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
  108.  
  109. Representing the digits 0 through 15.
  110.  
  111. Hexadecimal system uses powers of 16. For example:
  112. &H19 (hexadecimal) represents 25 decimal. Let's see why.
  113. Starting from the right the power is 1. Therefore 9 X 1 = 9
  114. Moving left the next is power is 16. Therefore 1 X 16 = 16
  115. And 9 + 16 = 25.
  116.  
  117. Let's try another. This time &HFF (hexadecimal)
  118. Again starting from the right (F=15) 15 X 1= 15
  119. Moving left 15 X 16 = 240.
  120. And 240 + 15 = 255
  121.  
  122. So far we have looked at single byte hex values. Let's look at
  123. a 16 bit hex value. Remember 8 bits to the byte? Now we look at
  124. two adjoining bytes, or sixteen bits.
  125.  
  126. &H1902 (hexadecimal) represents 6402 decimal.
  127.  
  128. Again starting from the right 2 X 1= 2
  129. Moving left 0 X 16 = 0
  130. Moving left again <16 X 16 =256> 9 X 256 = 2304
  131. Moving left again <16 X 256 = 4096> 1 X 4096 = 4096
  132. And 2 + 0 + 2304 + 4096 = 6402
  133.  
  134. In basic hex values are preceeded by &H. For example &HFF or &H1902
  135. In basic hex values can be determined by the command PRINT &HFF
  136. or PRINT &H1902.
  137.  
  138. Decimal to hex is accomplished by PRINT HEX$(255)
  139. or PRINT HEX$(1902).
  140.  
  141. Now let's look at the individual bits within a byte.
  142.  
  143. Remember there are 8 bits to the byte and reading from Right
  144. to Left they increase in power by the power of 2.
  145.  
  146. Binary notation reflects set bits with a 1. Non set bits with a 0.
  147. Let's look at one.
  148.  
  149. 1 0 0 0 1 0 0 1 (This byte represents 137)
  150. As with hex we start at the right.
  151.  
  152. 1 X 1= 1
  153. Moving left 2 X 0 = 0
  154. Moving left again 4 X 0 = 0
  155. Moving left again 8 X 1 = 8
  156. Moving left again 16 X 0 = 0
  157. Moving left again 32 X 0 = 0
  158. Moving left again 64 X 0 = 0
  159. Moving left again 128 X 1 = 128
  160.  
  161. And 1 + 0 + 0 + 8 + 0 + 0 + 0 + 128 = 137
  162.  
  163.                      Logical Operators <AND> <OR>
  164.  
  165. When you AND two numbers the results are in a new third number.
  166. For example:
  167. a = 137
  168. b = 105
  169. c = a AND b
  170.  
  171. 1 0 0 0 1 0 0 1  This represents A <137>
  172. 0 1 1 0 1 0 0 1  This represents B <105>
  173.  
  174. 0 0 0 0 1 0 0 1  This represents C <9>
  175.  
  176. What occurs when you AND two numbers is that the computer compares
  177. the bits within the first number against the bits in the second number.
  178. If the bits are the same then they will remain the same in the third
  179. number.
  180. If they are not the same then the equivalent bits will be 0 in the
  181. third number.
  182.  
  183.  
  184.                                "Logical OR
  185.  
  186. What occurs when you OR two numbers is that the computer compares
  187. the bits within the first number against the bits in the second number.
  188. If the bits are the same they will remain the same in the third number.
  189. If they are not the same then the bits will be 1 in the third number.
  190.  
  191. For example:
  192. A=122
  193. B=15
  194. C=A OR B
  195.  
  196. 0 1 1 1 1 0 1 0   This represents A <122>
  197. 0 0 0 0 1 1 1 1   This represents B <15>
  198.  
  199. 0 1 1 1 1 1 1 1   This represents C <127>
  200.  
  201. This quick little reference document composed by Earl Montgomery
  202. I hope it proves to be of some use to you.
  203.  
  204. '
  205.  
  206.  
  207.  From:  CHARLES GRAHAM            Sent: 03-28-93 15:08
  208.    To:  ALL                       Rcvd: -NO-
  209.    Re:  1 OF 6 AMORTIZE.BAS
  210.  
  211. 'Begin AMORTIZE.BAS Message 01
  212. '
  213. 'AMORTIZE.BAS -- CHARLES GRAHAM, POB 58634, ST.LOUIS, MO 63158
  214. totint# = 0
  215. pg = 0
  216. totprin# = 0
  217. yrct = 0
  218. COLOR 10, 1
  219. GOSUB logo
  220. LOCATE 1, 1
  221. LINE INPUT ; "Enter client name(s) [40 char max] ====> "; client$
  222. validated$ = "off"
  223. loball = 1
  224. hiball# = 9999999.99#
  225. decimals = 1
  226. WHILE validated$ = "off"
  227.     GOSUB logo
  228.     LOCATE 1, 1
  229.     LINE INPUT ; "Enter amount to be financed ====> "; amt$
  230.     quan$ = amt$
  231.     GOSUB validate
  232. WEND
  233. amt# = VAL(amt$)
  234. prinbal# = amt#
  235. validated$ = "off"
  236. loball = 1
  237. hiball# = 25
  238. decimals = 1
  239. WHILE validated$ = "off"
  240.     GOSUB logo
  241.     LOCATE 1, 1
  242.     LINE INPUT ; "Enter APR [1-25] ====> "; rate$
  243.     quan$ = rate$
  244.     GOSUB validate
  245. WEND
  246. rate = VAL(rate$)
  247. i = rate / 1200
  248. validated$ = "off"
  249. loball = 1
  250. hiball# = 480
  251. decimals = 0
  252. WHILE validated$ = "off"
  253.     GOSUB logo
  254.     LOCATE 1, 1
  255.     LINE INPUT ; "Enter term of loan [1-480 months] ====> "; n$
  256.     quan$ = n$
  257.     GOSUB validate
  258. WEND
  259. n = VAL(n$)
  260. pmt# = amt# / ((1 - ((1 + i) ^ (-n))) / i)
  261. pmt# = INT((pmt# * 100) + .5) / 100
  262. validated$ = "off"
  263. loball = 1
  264. hiball# = 12
  265. decimals = 0
  266. WHILE validated$ = "off"
  267.     GOSUB logo
  268.     LOCATE 1, 1
  269.     LINE INPUT ; "Enter month first payment is due [1-12] ====> "; mo$
  270.     quan$ = mo$
  271.     GOSUB validate
  272. WEND
  273. mo = VAL(mo$)
  274. validated$ = "off"
  275. loball = 0
  276. hiball# = 99
  277. decimals = 0
  278. WHILE validated$ = "off"
  279.     GOSUB logo
  280.     LOCATE 1, 1
  281.     LINE INPUT ; "Enter year first payment is due [00-99] ====> "; yr$
  282.     quan$ = yr$
  283.     GOSUB validate
  284. WEND
  285. yr = VAL(yr$)
  286. GOSUB logo
  287. LOCATE 1, 1
  288. PRINT "Send output to screen or printer [s/p] ====> ";
  289. o$ = ""
  290. WHILE o$ <> "s" AND o$ <> "p"
  291.     o$ = INKEY$
  292.     IF o$ = "S" THEN
  293.         o$ = "s"
  294.     ELSE
  295.         IF o$ = "P" THEN
  296.             o$ = "p"
  297.         END IF
  298.     END IF
  299. WEND
  300. PRINT o$
  301. GOSUB logo
  302. LOCATE 1, 1
  303. IF o$ = "p" THEN
  304.     LOCATE 13, 29
  305.     PRINT "AMORTIZE is printing ... ";
  306. END IF
  307. GOSUB printheaders
  308. FOR ct = 1 TO n
  309.     intr# = INT((i * prinbal# * 100) + .5) / 100
  310.     prin# = pmt# - intr#
  311.     IF mo >= 13 THEN
  312.         IF o$ = "s" THEN
  313.             GOSUB pause
  314.             FOR x = 9 TO 20
  315.                 LOCATE x, 1
  316.                 PRINT "                                                                                ";
  317.             NEXT x
  318.         END IF
  319.         mo = 1
  320.         yr = yr + 1
  321.         IF yr > 99 THEN
  322.             yr = 0
  323.         END IF
  324.     END IF
  325.     totint# = totint# + intr#
  326.     totprin# = totprin# + prin#
  327.     prinbal# = amt# - totprin#
  328.     IF mo = 1 THEN
  329.         IF o$ = "s" THEN
  330.             LOCATE 9, 1
  331.         ELSE
  332.             IF ct <> 1 THEN
  333.                 LPRINT
  334.                 yrct = yrct + 1
  335.                 IF yrct / 4 = INT(yrct / 4) THEN
  336.                     GOSUB printheaders
  337.                 END IF
  338.             END IF
  339.         END IF
  340.     END IF
  341.     IF o$ = "s" THEN
  342.         PRINT USING "###"; ct;
  343.         PRINT TAB(5); " ";
  344.         PRINT USING "##"; mo;
  345.         PRINT "/";
  346.         IF yr > 9 THEN
  347.             PRINT USING "##"; yr;
  348.         ELSE
  349.             PRINT "0" + RIGHT$(STR$(yr), 1);
  350.         END IF
  351.         PRINT TAB(12); " ";
  352.         PRINT USING "#######.##"; intr#;
  353.         PRINT TAB(26); " ";
  354.         PRINT USING "#######.##"; prin#;
  355.         PRINT TAB(40); " ";
  356.         PRINT USING "#######.##"; totint#;
  357.         PRINT TAB(54); " ";
  358.         PRINT USING "#######.##"; totprin#;
  359.         PRINT TAB(68); " ";
  360.         PRINT USING "#######.##"; prinbal#
  361.     ELSE
  362.         LPRINT USING "###"; ct;
  363.         LPRINT TAB(5); " ";
  364.         LPRINT USING "##"; mo;
  365.         LPRINT "/";
  366.         IF yr > 9 THEN
  367.             LPRINT USING "##"; yr;
  368.         ELSE
  369.             LPRINT "0" + RIGHT$(STR$(yr), 1);
  370.         END IF
  371.         LPRINT TAB(12); " ";
  372.         LPRINT USING "#######.##"; intr#;
  373.         LPRINT TAB(26); " ";
  374.         LPRINT USING "#######.##"; prin#;
  375.         LPRINT TAB(40); " ";
  376.         LPRINT USING "#######.##"; totint#;
  377.         LPRINT TAB(54); " ";
  378.         LPRINT USING "#######.##"; totprin#;
  379.         LPRINT TAB(68); " ";
  380.         LPRINT USING "#######.##"; prinbal#
  381.     END IF
  382.     mo = mo + 1
  383. NEXT ct
  384. IF o$ = "s" THEN
  385.     GOSUB pause
  386. ELSE
  387.     LPRINT CHR$(12);
  388.     LPRINT CHR$(12);
  389. END IF
  390. COLOR 7, 0
  391. CLS
  392. END
  393. ' ** Replace this with a blank line **
  394. printheaders:
  395. IF o$ = "s" THEN
  396.     PRINT client$
  397.     PRINT "Amount of loan         = ";
  398.     PRINT USING "#######.##"; amt#
  399.     PRINT "Monthly payment        = ";
  400.     PRINT USING "#######.##"; pmt#
  401.     PRINT "Annual Percentage Rate = ";
  402.     PRINT USING "#####.####"; rate
  403.     PRINT "Term of loan [months]  =        ";
  404.     PRINT USING "###"; n
  405.     PRINT
  406.     PRINT "PMT   DATE    INT PAID     PRIN PAID  TOT INT " + _
  407. "PAID   TOT PRIN PD  PRINCIPL BAL"
  408.     LOCATE 22, 19
  409.     PRINT "Press ESCape to end, other key to continue";
  410.     LOCATE 9, 1
  411. ELSE
  412.     pg = pg + 1
  413.     LPRINT CHR$(12);
  414.     LPRINT client$;
  415.     LPRINT TAB(71); "Page"; pg
  416.     LPRINT "Amount of loan         = ";
  417.     LPRINT USING "#######.##"; amt#
  418.     LPRINT "Monthly payment        = ";
  419.     LPRINT USING "#######.##"; pmt#
  420.     LPRINT "Annual Percentage Rate = ";
  421.     LPRINT USING "#####.####"; rate
  422.     LPRINT "Term of loan [months]  =        ";
  423.     LPRINT USING "###"; n
  424.     LPRINT
  425.     LPRINT "PMT   DATE    INT PAID     PRIN PAID  TOT INT  PAID   TOT PRIN PD  PRINCIPL BAL"
  426.     LPRINT
  427. END IF
  428. RETURN
  429. ' ** Replace this with a blank line **
  430. validate:
  431. errct = 0
  432. decpts = 0
  433. FOR x = 1 TO LEN(quan$)
  434.     IF (MID$(quan$, x, 1) < "0" AND MID$(quan$, x, 1) <> ".") OR MID$(quan$, x, 1) > "9" THEN
  435.         errct = errct + 1
  436.     END IF
  437.     IF MID$(quan$, x, 1) = "." THEN
  438.         decpts = decpts + 1
  439.     END IF
  440. NEXT x
  441. IF decpts > decimals THEN
  442.     errct = errct + 1
  443. END IF
  444. IF errct = 0 THEN
  445.     IF VAL(quan$) < loball OR VAL(quan$) > hiball# THEN
  446.         errct = errct + 1
  447.     END IF
  448. END IF
  449. IF errct = 0 THEN
  450.     validated$ = "on"
  451. END IF
  452. RETURN
  453. ' ** Replace this with a blank line **
  454. pause:
  455. a$ = ""
  456. WHILE a$ = ""
  457.     a$ = INKEY$
  458. WEND
  459. IF a$ = CHR$(27) THEN
  460.     COLOR 7, 0
  461.     CLS
  462.     END
  463. END IF
  464. RETURN
  465. ' ** Replace this with a blank line **
  466. logo:
  467. CLS
  468. LOCATE 24, 17
  469. PRINT ". AMORTIZE.BAS . For non-commercial use only .";
  470. LOCATE 25, 17
  471. PRINT "Charles Graham, POB 58634, St. Louis, MO 63158";
  472. RETURN
  473. '
  474.  
  475.  
  476.  
  477. Msg #:  8929                      QUIKBAS Subboard
  478.  From:  HANK TASSIN               Sent: 03-28-93 12:15
  479.    To:  TOM COAKLEY               Rcvd: -NO-
  480.    Re:  ARROW KEYS
  481.  
  482.  At the beginning of Time, you scribbled to All:
  483.  
  484.  TC> On the new keyboards you have 2 sets of arrow keys. The one on the
  485.  TC> numeric keypad and then one by itself. I can not figure out how to
  486. get
  487.  TC> my Quick Basic 4.5 programs to accept input from the ones NOT on
  488. the
  489.  TC> numeric keypad. This ticks me off to no end. If ANYONE knows how
  490. to do
  491.  TC> this I would be forever gratefull for some E-Mail explaining how
  492. it is
  493.  TC> done.
  494.  
  495. Hiya Tom,
  496.  
  497. Here is a piece of code I used to do that, although it could probably
  498. be made alot cleaner but appending CHR$(0) to the INKEY$ routine
  499. instead of grabbing RIGHT$ like I am doing, but it should get you
  500. started.
  501.  
  502. BTW, it even recognizes the NumLock key and stops "moving" when a
  503. number is pressed from the keypad.
  504.  
  505. CONST ENTER% = 13
  506. CONST ESC% = 27
  507. CONST RIGHT% = 28
  508. CONST LEFT% = 29
  509. CONST UP% = 30
  510. CONST DOWN% = 31
  511. CONST SPACEHIT% = 32
  512. CONST GOHOME% = 71
  513. CONST GREYUP% = 72
  514. CONST GOPAGEUP% = 73
  515. CONST GREYMINUS% = 74
  516. CONST GREYLEFT% = 75
  517. CONST GOCENTER% = 76
  518. CONST GREYRIGHT% = 77
  519. CONST GREYPLUS% = 78
  520. CONST GOENDKEY% = 79
  521. CONST GREYDOWN% = 80
  522. CONST GOPAGEDOWN% = 81
  523.  
  524. FINISHED% = 0
  525. DO WHILE FINISHED% < 1
  526.   DO
  527.     TEMP$ = INKEY$
  528.   LOOP WHILE TEMP$ = ""
  529.   MOVE% = ASC(RIGHT$(TEMP$, 1))
  530.   SELECT CASE MOVE%
  531.     CASE ENTER%
  532.       CALL SPACEOUT
  533.     CASE etc.....
  534.   END CASE
  535.  
  536. '
  537.  
  538.  
  539.  
  540.        
  541. ****************************************************************
  542.  
  543.  
  544.  
  545.     *     The QUIK_BAS List of Frequently Asked Questions with
  546.  
  547.     *             Some Simple Public Domain Solutions
  548.  
  549.  
  550. ****************************************************************
  551.  
  552.  
  553. TABLE OF CONTENTS:
  554.  
  555.         q1.0    The BASICS of BASIC
  556.                 s1.0    QUIKSORT.BAS    -- recursive quicksort SUB
  557.  
  558.         q2.0    Commonly Requested Routines
  559.                 s2.0    HUTHSORT.BAS    -- iterative quicksort SUB
  560.                 s3.0    BISEARCH.BAS    -- binary search FUNCTION
  561.  
  562.         q3.0    Advanced Topics         -- "Hashing in QuickBASIC"
  563.                 t1.0    Hashing Collision Table
  564.                 s4.0    FSTPRIME.BAS    -- generates 4K+3 prime number
  565.                 t2.0    List Management System Ratings
  566.                 s5.0    WORDHASH.BAS    -- word distribution counter
  567.  
  568.         q4.0    Structured BASIC Techniques
  569.  
  570.  
  571. NOTE:   All source remains the property of those who originally wrote
  572.         it, as understood by Canadian, American, and International
  573.         Treaty.
  574.  
  575.         The text portion of this file itself is hereby released into the
  576.         "Public Domain" for the purposes of education and enlightenment.
  577.  
  578.  
  579. Q1.0    The BASICS of BASIC:
  580.  
  581. Q1.4    Okay, I've figured out FUNCTIONs and SUBs, and have even
  582.         started using them with some kind of skill.  Now, thing is, I
  583.         come up to this thing called 'recursion.'  What's this all
  584.         about, and can you show me some practical application of it?
  585.  
  586. A1.4    There is an old joke about the cryptic nature of dictionaries
  587.         that goes something like this:
  588.  
  589.         re'CUR'sion (noun) 1. see recursion
  590.  
  591.         Actually, that's a pretty sad joke.  One computer scientist's
  592.         definition states:
  593.  
  594.         "... a recursive algorithm is one that contains a copy of itself
  595.         within one of its instructions.  Thus, a recursive algorithm is
  596.         reminiscent of a set of mirrors in which you can see yourself
  597.         looking at yourself looking at yourself."  [J. Glenn Brookshear]
  598.  
  599.         Recursion is a powerful programming tool, and any comprehensive
  600.         programming language allows it.  QuickBASIC and its dialects are
  601.         no exception.  A simple example of recursion:
  602.  
  603.         SUB recurse
  604.             recurse
  605.         END SUB
  606.  
  607.         This thing will go in circles until the stack is full, crashing
  608.         the program should it ever be called.  It illustrates two of the
  609.         main pitfalls of recursion:
  610.  
  611.              1. recursion in QuickBASIC eats the stack for breakfast
  612.              2. there must be a terminating condition to exit the loop
  613.  
  614.         Since each call to a SUB or FUNCTION does some pushing to the
  615.         stack, it must always be remembered that recursive routines will
  616.         require a bit of the stack for every instance they are called.
  617.         It is sometimes hard to know in advance how many times a
  618.         recursive routine will end up calling itself, and therefore, one
  619.         cannot know with any accuracy how much a given recursive routine
  620.         will decide to rob from the stack.  Be warned!
  621.  
  622.         This also leads to the next issue: there must ALWAYS be a
  623.         terminating condition to exit the loop.  Sometimes it is easy to
  624.         overlook this point.  Consider the above simple example.  It
  625.         never stops calling itself, does it?  Were a theoretical
  626.         computer to exist that had a theoretically infinitely large
  627.         stack that could never be consumed by even the deepest level of
  628.         recursion, what happens if that routine goes off into a corner
  629.         and keeps calling itself?  It results in a permanent time out
  630.         known as a crash. (The moral of this?  A bug on a i486 system is
  631.         still a bug, just a bug that happens sooner.)
  632.  
  633.         An example of a terminating condition added to the above code:
  634.  
  635.         SUB recurse(n%)
  636.         n% = n% + 1
  637.         IF n% < 10 THEN
  638.                 recurse
  639.         END IF
  640.         END SUB
  641.  
  642.         This SUB will call itself only until n% is equal to ten, at
  643.         which point, it will reach its terminating state, and be
  644.         finished on its job.  This is a simple example, I admit, but
  645.         NEVER forget to include a terminating statement in your
  646.         recursive routines, or you will pay for it with a crash.
  647.  
  648.         Now that we have that out of the way, let's kill two birds with
  649.         one stone.  (It could be argued, in fact that the act of killing
  650.         two birds with only one stone probably involves recursion
  651.         somewhere in the solution.)  Everyone wants to know a good
  652.         QuickSort algorithm, and most implementations of that use
  653.         recursion.  So, a modified version of the QuickSort SUB from
  654.         Microsoft, one that sorts an array passed to it:
  655.  
  656. S1.0    QUIKSORT.BAS [F210S01.BAS]
  657.  
  658. DEFINT A-Z
  659. SUB QuickSortSTR (Array() AS STRING, Low, High)
  660. '            /^\              /^\
  661. '             |                |
  662. '    Change these to any BASIC data type for this routine to
  663. '    handle other types of data arrays other than strings.
  664. '
  665. '============================== QuickSortXXX ================================
  666. '  QuickSortXXX works by picking a random "pivot" element in Array(), then
  667. '  moving every element that is bigger to one side of the pivot, and every
  668. '  element that is smaller to the other side.  QuickSortXXX is then  called
  669. '  recursively with the two subdivisions created by the pivot.  Once the
  670. '  number of elements in a subdivision reaches two, the recursive calls end
  671. '  and the array is sorted.
  672. '===========================================================================
  673. '
  674. '            Microsoft's source code modified as needed
  675. '
  676.  
  677. STATIC BeenHere
  678.  
  679. IF NOT BeenHere THEN
  680.         Low = LBOUND(Array)
  681.         High = UBOUND(Array)
  682.         BeenHere = -1
  683. END IF
  684.  
  685. DIM Partition AS STRING  ' Change STRING to any BASIC data type
  686.                          ' for this QuickSort routine to work with
  687.                          ' things other than strings.
  688.  
  689.    IF Low < High THEN
  690.  
  691.       ' Only two elements in this subdivision; swap them if they are out
  692.       ' of order, then end recursive calls:
  693.  
  694.       IF High - Low = 1 THEN ' we have reached the terminating condition!
  695.          IF Array(Low) > Array(High) THEN
  696.             SWAP Low, High
  697.             BeenHere = 0
  698.          END IF
  699.       ELSE
  700.  
  701.          ' Pick a pivot element at random, then move it to the end:
  702.          RandIndex = INT(RND * (High - Low + 1)) + Low
  703.          SWAP Array(High), Array(RandIndex)
  704.          Partition = Array(High)
  705.          DO
  706.  
  707.             ' Move in from both sides towards the pivot element:
  708.             I = Low: J = High
  709.             DO WHILE (I < J) AND (Array(I) <= Partition)
  710.                I = I + 1
  711.             LOOP
  712.             DO WHILE (J > I) AND (Array(J) >= Partition)
  713.                J = J - 1
  714.             LOOP
  715.  
  716.             ' If we haven't reached the pivot element, it means that two
  717.             ' elements on either side are out of order, so swap them:
  718.             IF I < J THEN
  719.                SWAP Array(I), Array(J)
  720.             END IF
  721.          LOOP WHILE I < J
  722.  
  723.          ' Move the pivot element back to its proper place in the array:
  724.          SWAP Array(I), Array(High)
  725.  
  726.          ' Recursively call the QuickSortSTR procedure (pass the smaller
  727.          ' subdivision first to use less stack space):
  728.          IF (I - Low) < (High - I) THEN
  729.             QuickSortSTR Array(), Low, I - 1
  730.             QuickSortSTR Array(), I + 1, High
  731.          ELSE
  732.             QuickSortSTR Array(), I + 1, High
  733.             QuickSortSTR Array(), Low, I - 1
  734.          END IF
  735.       END IF
  736.    END IF
  737. END SUB
  738.  
  739. '=======>8 SAMPLE 1.0 ENDS HERE 8<=========
  740.  
  741. Q1.5    So that's how to use recursion!  That's great!  I think I'm
  742.         starting to get a hang of things with QuickBASIC now, thanks.
  743.         But, how is it possible for it to call itself over and over
  744.         like that without all those variables interfering with
  745.         each other?  I mean, I'm kind of used to GW-BASIC, and well,
  746.         I just can't figure out why all those High and Low variables
  747.         don't just write over one another.  My docs say something about
  748.         local and global scope, but it's all kind of confusing.  What's
  749.         the real difference between local, STATIC, COMMON, SHARED, COMMON
  750.         SHARED, and all other flavors of variables?
  751.  
  752. A1.5    Beginners with QuickBASIC sometimes have a hard time decrypting
  753.         all of the different types of variable scope.  Microsoft hasn't
  754.         really helped anything with all the funny names for variable
  755.         scope.  GLOBAL would have made more sense than SHARED for most.
  756.         Okay, let's look at how the QuickBASIC program is inevitably
  757.         structured:
  758.  
  759.                 1.  First, there is the 'module' level.  That is the
  760.                     main part of the QuickBASIC program, the part where
  761.                     execution starts, and most programmers declare their
  762.                     constants, and put their main documentation.
  763.  
  764.                 2.  Second, there is the SUB and FUNCTION level.  Each
  765.                     SUB and FUNCTION could be thought of as a miniprogram
  766.                     unto itself.  That's why SUBs are called that:
  767.                     subprogram.
  768.  
  769.                 3.  Third, if you write bigger programs, you may actually
  770.                     have two or more modules, each one having its own
  771.                     SUBs and FUNCTIONs.
  772.  
  773.         Okay, then, any variable used at the modular level, or level 1, is
  774.         accessible, or in the 'scope' of the modular level.  If there is
  775.         a variable called Foo at the modular level, with a value of 7, then
  776.         any Foo at the SUB or FUNCTION level could also be called Foo,
  777.         without interfering with the modular Foo.  Think of each module
  778.         level variable and each SUB and FUNCTION variable as being on
  779.         different continents.  They can have the same name with no problem.
  780.  
  781.         But, suppose you want a SUB or FUNCTION to have access to the
  782.         Foo that was declared at the modular level.  This is where the
  783.         SHARED declarator comes in.  In the SUB somesubprog, to have
  784.         access to the Foo that was declared at the modular level, just
  785.         add the declaration:
  786.  
  787.         SHARED Foo
  788.  
  789.         Any SUB or FUNCTION that doesn't want to have access to the
  790.         modular Foo doesn't have to declare it as SHARED.  This is a
  791.         powerful feature, once you get the hang of it and feel confident
  792.         enough to use it wisely.
  793.  
  794.         Now, suppose that you want a number of your SUBs or FUNCTIONs to
  795.         have access to a common group of variables.  At the modular
  796.         level, the declaration would be:
  797.  
  798.         DIM SHARED Foo
  799.  
  800.         This would give ALL of the SUBs and FUNCTIONs of a given module
  801.         access to the variable Foo.  Any access of Foo at any level will
  802.         alter the global variable.
  803.  
  804.         Now, suppose you have a multimodule program that has FIRST.BAS
  805.         and SECOND.BAS linked together.  Suppose you want them to
  806.         communicate with one another via a common global variable.  This
  807.         is where COMMON SHARED comes in.
  808.  
  809.         Now that we've covered this, there is the issue of the STATIC
  810.         declarator.  Normally, variables at the SUB and FUNCTION level
  811.         are dynamic, which means they disappear when the routine returns
  812.         to the place that it was called from.  By declaring a variable
  813.         STATIC, we can be assured that whatever the variable's value was
  814.         when we left, it will be when we return.  To declare only a few
  815.         of the variables as STATIC, use the form:
  816.  
  817.         SUB FooSub ()
  818.         STATIC Variable1, Variable2, etc.
  819.         :
  820.         :
  821.         END SUB
  822.         But, if you want ALL the variables to be STATIC, use the following
  823.         method:
  824.  
  825.         SUB FooSub () STATIC
  826.         :
  827.         :
  828.         :
  829.         END SUB
  830.  
  831.         There are certain speed advantages to STATIC SUBs and FUNCTIONs,
  832.         since variables are not created on the stack, but that is a more
  833.         advanced issue.
  834.  
  835.         So, in summary:
  836.  
  837.         1.  SHARED allows SUBs and FUNCTIONs to use modular variables,
  838.         2.  COMMON allows modules to share variables between themselves,
  839.         3.  STATIC allows variables to retain their value between
  840.             calls to the SUB or FUNCTION in question.
  841.  
  842. Q2.0    Commonly Requested Routines:
  843.  
  844. Q2.4    Okay, I've looked the whole thing over and I've realized
  845.         something: the recursive QuickSortXXX routine eats the stack up
  846.         pretty fast.  Is there another way?  Is there a way to implement
  847.         a QuickSort SUB without using recursion?
  848.  
  849. A2.4    Yes, indeed there is.  Cornel Huth implemented an iterative
  850.         quicksort algorithm, which I then tweaked a bit.  It is actually
  851.         a bit faster than the other, and doesn't use too much of the stack.
  852.         It accomplishes this by using an array to simulate a stack. The
  853.         modified version follows:
  854.  
  855. S2.0    HUTHSORT.BAS [P210S02.BAS]
  856.  
  857. ' HUTHSORT.BAS written by Cornel Huth
  858. ' Iterative QuickSort Routine
  859. '
  860. SUB subHuthSortSTR (Array() AS STRING)
  861. '               ^  TWEAK THESE    ^
  862. '               | FOR OTHER TYPES |
  863. '               `--+--------------'
  864. '                  V
  865.   DIM compare AS STRING
  866.  
  867. TYPE StackType
  868.   low AS INTEGER
  869.   hi AS INTEGER
  870. END TYPE
  871.  
  872. DIM aStack(1 TO 128) AS StackType
  873.  
  874.   StackPtr = 1
  875.   aStack(StackPtr).low = LBOUND(Array)
  876.   aStack(StackPtr).hi = UBOUND(Array)
  877.   StackPtr = StackPtr + 1
  878.  
  879.   DO
  880.     StackPtr = StackPtr - 1
  881.     low = aStack(StackPtr).low
  882.     hi = aStack(StackPtr).hi
  883.     DO
  884.       i = low
  885.       j = hi
  886.       mid = (low + hi) \ 2
  887.       compare = Array(mid)
  888.       DO
  889.         DO WHILE Array(i) < compare
  890.           i = i + 1
  891.         LOOP
  892.     DO WHILE Array(j) > compare
  893.           j = j - 1
  894.         LOOP
  895.         IF i <= j THEN
  896.           SWAP Array(i), Array(j)
  897.           i = i + 1
  898.           j = j - 1
  899.         END IF
  900.  
  901.       LOOP WHILE i <= j
  902.       IF j - low < hi - i THEN
  903.         IF i < hi THEN
  904.           aStack(StackPtr).low = i
  905.           aStack(StackPtr).hi = hi
  906.           StackPtr = StackPtr + 1
  907.         END IF
  908.         hi = j
  909.       ELSE
  910.         IF low < j THEN
  911.           aStack(StackPtr).low = low
  912.           aStack(StackPtr).hi = j
  913.           StackPtr = StackPtr + 1
  914.         END IF
  915.         low = i
  916.       END IF
  917.     LOOP WHILE low < hi
  918.     'IF StackPtr > maxsp THEN maxsp = StackPtr
  919.   LOOP WHILE StackPtr <> 1
  920. END SUB
  921.  
  922. =======>8 SAMPLE 2.0 ENDS HERE 8<=========
  923.  
  924. Q2.5    Now that I've got so many neat ways to sort a list, I'd sure like
  925.         to be able to locate an entry in it quickly.  I hear that a binary
  926.         search is fast, but I just can't figure out how to do that.  How
  927.         do I do a binary search?
  928.  
  929. A2.5    Binary searches are the fastest overall search method for
  930.         standard sorted lists.  Such lists can be divided in two, looked
  931.         at, and divided again as necessary.  A good search method is
  932.         demonstrated here:
  933.  
  934. S3.0    BISEARCH.BAS [F210S03.BAS]
  935.  
  936.  
  937. DEFINT A-Z
  938. FUNCTION BiSearchSTR (Find AS STRING, Array() AS STRING)
  939.  
  940. Min = LBOUND(Array)             'start at first element
  941. Max = UBOUND(Array)             'consider through last
  942.  
  943. DO
  944.   Try = (Max + Min) \ 2         'start testing in middle
  945.  
  946.   IF Array(Try) = Find THEN     'found it!
  947.     BiSearch = Try              'return matching element
  948.     EXIT DO                     'all done
  949.   END IF
  950.  
  951.   IF Array(Try) > Find THEN     'too high, cut in half
  952.     Max = Try - 1
  953.   ELSE
  954.     Min = Try + 1               'too low, cut other way
  955.   END IF
  956. LOOP WHILE Max >= Min
  957.  
  958. END FUNCTION
  959.  
  960. =======>8 SAMPLE 3.0 ENDS HERE 8<=========
  961.  
  962. Q3.0    Advanced Topics -- "Hashing in QuickBASIC"
  963. Q3.1    That's pretty fast!  I was so used to doing a sequential search
  964.         on an unsorted list.  Now that I have the QuickSort and the
  965.         BiSearch routines, I can use them as a pair for faster list
  966.         searches.
  967.  
  968.         The thing is, as soon as I want to add something to the list, it
  969.         puts everything out of order by only one entry, and that hardly
  970.         seems worth sorting all over again, even with something as fast
  971.         as Cornel Huth's iterative QuickSort algorithm.  Are there any
  972.         alternatives to this way of doing things?  I've heard talk of
  973.         something called 'hashing' but I don't have any idea of what
  974.         that is all about.  How would I use hashing to avoid having to
  975.         either resort the list, or use a slow insertion algorithm?
  976.         Insertion is horrendously slow with disk files.
  977.  
  978. A3.1    Hashing is a very efficient method of record access, be it in
  979.         RAM or be it with a disk file.  Basically, hashed arrays or data
  980.         files can be quickly searched for a given item by a key index.
  981.         Whenever you have to add an item to the list, you can at
  982.         lightening speed, and since hashing "sorts" the array
  983.         on-the-fly, as it were, there is no need to push records around
  984.         to add new items to a hashed record.
  985.  
  986.         The first concept you must understand with hashing is the key
  987.         index. Every data structure you design with hashing in mind has
  988.         to have one field that is unique.  This is a prerequisite that
  989.         you just can't get around.  Of course, you could actually
  990.         combine several fields to generate this unique key, which
  991.         effectively serves the same purpose.  A good application of this
  992.         is a Fidonet nodelist that uses the node address as the hashing
  993.         key.  No two alike in theory.
  994.  
  995.         But just how does this key work?  First of all, let's take a
  996.         look at the Fidonet example.  Every full Fidonet address is
  997.         unique to one node.  Assume that the full nodelist has about
  998.         15000 entries. Okay, if you want a hashing table to hold 15000
  999.         unique entries, then research has shown that the table should be
  1000.         at least 30% greater than the number of entries in it.  That
  1001.         would make 19500 table entries.  This means that 4500 entries in
  1002.         the list will be left empty for best hashing results.
  1003.  
  1004.         Now, another problem comes up.  How does the key come into
  1005.         play? Well, let's look at a simple key: 1153999.  Since the list
  1006.         is 19500 long, we certainly can't just put this in record
  1007.         1153999. Hashing involves dividing the key by the table size and
  1008.         taking the remainder and using that as the record number:
  1009.  
  1010.                            59
  1011.                     ----------  R 3499
  1012.                19500) 1153999
  1013.  
  1014.  
  1015.         Okay, 3499 is the record number in which we would put the data.
  1016.         This is the basic idea behind hashing.  There is a trouble,
  1017.         however. Collision occurs whenever a node address, when divided
  1018.         by 19500 has a remainder of 3499.  That 'bucket' is already
  1019.         full!  So, what to do?  Generate another bucket number, see if
  1020.         that bucket is full, and if it is, keep generating new buckets
  1021.         until we find an empty bucket.
  1022.  
  1023.         To find an item in a hashed table, we get its key, divide by the
  1024.         table size, and look at the bucket that is represented by the
  1025.         remainder.  If that isn't the one, we generate the next bucket
  1026.         address, until we arrive at an empty bucket.  If we encounter
  1027.         the correct key BEFORE we arrive at an empty bucket, then we've
  1028.         found our entry.  If we arrive at an empty bucket, the record is
  1029.         not in the table.  And there you have hashing.
  1030.  
  1031.         A well designed hashing table will yield this number of
  1032.         collisions per insertion or search:
  1033.  
  1034.  
  1035. T1.0    Hashing Collision Table
  1036.  
  1037.         TABLE FULLNESS          COLLISIONS
  1038.         ==================================
  1039.              50%                   2.0
  1040.              60%                   2.5
  1041.              70%                   3.3
  1042.              90%                  10.0
  1043.  
  1044.  
  1045. =======>8 TABLE 1.0 ENDS HERE 8<=========
  1046.  
  1047.         That shows better results than even the binary search, with
  1048.         large lists!
  1049.  
  1050.         Research has shown that the most efficient hashing tables, that
  1051.         is, the ones with the least number of collisions, have a prime
  1052.         number of entries.  A table size of 1019 should produce less
  1053.         collisions than one of 1000.  Research has also shown that if
  1054.         the prime is of the form 4K+3, where K is any positive integer,
  1055.         then collisions are reduced even further.  1019 also meets this
  1056.         second requirement.  But, since a table size twice the size of
  1057.         the maximum number of entries it will ever hold is inefficient,
  1058.         the 4K+3 criterion should be abandoned at a certain point in
  1059.         favor of any prime number.  Since most of us aren't idiot
  1060.         savants who can just come up with that number to suit our needs,
  1061.         here is a FUNCTION, written by Charles Graham, that accepts the
  1062.         maximum number of entries a table will have, and returns the
  1063.         proper type of prime number, to be used as a hashing table size:
  1064.  
  1065. S4.0    FSTPRIME.BAS [F210S04.BAS]
  1066.  
  1067. DEFINT A-Z
  1068.  
  1069. ' This FUNCTION returns a prime number that is at least 30% greater than
  1070. ' threshold.  It will TRY to return a prime number that also fits into the
  1071. ' form 4K+3, where k is any integer, but if the prime number is twice the
  1072. ' size of the threshold, it will ignore this criterion.
  1073. '
  1074. '     Written by Charles Graham
  1075. '
  1076. FUNCTION funFirstPrime (threshold)
  1077. CONST TRUE = -1
  1078. CONST FALSE = NOT TRUE
  1079.  
  1080. tp30 = INT((threshold * 1.3) + .5)
  1081. IF tp30 / 2 = tp30 \ 2 THEN
  1082.     tp30 = tp30 + 1
  1083. END IF
  1084. c = tp30 - 2
  1085. IF c < 1 THEN
  1086.     c = 1
  1087. END IF
  1088. t2 = threshold * 2
  1089. DO
  1090.     c = c + 2
  1091.     FOR z = 3 TO SQR(c)
  1092.         ind = TRUE
  1093.         IF c / z = c \ z THEN
  1094.             ind = FALSE
  1095.             EXIT FOR
  1096.         END IF
  1097.     NEXT z
  1098.     IF ind THEN
  1099.         IF (c - 3) / 4 = INT((c - 3) / 4) OR c > t2 THEN
  1100.             funFirstPrime = c
  1101.             EXIT DO
  1102.         END IF
  1103.     END IF
  1104. LOOP
  1105. END FUNCTION
  1106.  
  1107. =======>8 SAMPLE 4.0 ENDS HERE 8<=========
  1108.  
  1109. Q3.1    How do I know when to use sequential searches, when to use
  1110.         binary searches, and when to use hashing?  Are there any sort
  1111.         of guidelines?
  1112.  
  1113. A3.1    Well, first let's consider where hashing is in its prime.
  1114.         (You'll pardon that one, okay?)  It is best suited to dynamic
  1115.         list generation where items need to be added on a regular basis,
  1116.         but not deleted, since deletion is fairly difficult to implement
  1117.         on a hashed list.  The main strength of a hashing system is its
  1118.         ability to quickly insert new items into the table in such a
  1119.         manner that they can be located quickly "on-the-fly."   (See
  1120.         T1.0 for the average number of collisions before locating the
  1121.         correct entry.)
  1122.  
  1123.         Since the collisions increase with the ratio of full
  1124.         buckets to empty buckets, and not with the size of the actual
  1125.         table involved, hashing is more efficient than even binary
  1126.         searches when lists start to become huge.  Also, because the
  1127.         binary method of searching demands a sorted list, insertion of
  1128.         items at a later time becomes very cumbersome, even with such
  1129.         techniques as the QuickSort and pushing all entries after the
  1130.         insertion up by one.  (Try that technique on a list of 30,000
  1131.         items, when you only want to add two new items that land near
  1132.         the beginning of the list, and you'll know what disk wear and
  1133.         tear is all about!)
  1134.  
  1135.         Typical applications of the hashing algorithm involve word
  1136.         distribution counts, dictionary table generators that involve
  1137.         dictionaries that will be added to dynamically, and things of
  1138.         that nature.
  1139.  
  1140.         Consider the word distribution count problem.  Each word is a
  1141.         unique key, and so is perfect for hashing.  Sequential methods
  1142.         only work well up until the table has so many entries in it that
  1143.         looking up entries in the table becomes a real effort. Remember,
  1144.         words already in the list do not need to be added twice. Binary
  1145.         methods allow for quick searching, but each case of a new word
  1146.         being added to the list requires a sort or cumbersome insertion.
  1147.         This takes time, if a text file is of even average length.
  1148.  
  1149.         Hashing, on the other hand, can increment the count of words
  1150.         already in the list, or add new words to the list, without the
  1151.         overhead of sorting, sequential searches, or push-type
  1152.         insertion.  Also, remember that entry deletion is a problem with
  1153.         hashing.  Word distribution counts NEVER require entries to be
  1154.         struck, and so are well-suited to hashing systems.
  1155.  
  1156.         A good rule of thumb to determine which method may be best for a
  1157.         given problem is to cosider the points on this table:
  1158.  
  1159. T2.0    List Management System Ratings
  1160.  
  1161.                                       List  Type
  1162.                         SEQUENTIAL      BINARY          HASHED
  1163.                 =====================================================
  1164. small list                  1              3              2
  1165. medium list                 3              1              2
  1166. large list                  3              2              1
  1167. huge list                   3              2              1
  1168.  
  1169. Insertion                   2              3              1
  1170. Modification                3              2              1
  1171. Deletion                    1              2              3
  1172. Browsing                    2              1              3
  1173.  
  1174.                      (Systems are ranked first, second, or third)
  1175.  
  1176. =======>8 TABLE 2.0 ENDS HERE 8<=========
  1177.  
  1178.         Using this table, we can see that the best method for short
  1179.         lists that require frequent deletions might be the sequential
  1180.         list.  The best for huge lists that require insertions,
  1181.         modifications, but not deletions (such as a nodelist index) is
  1182.         probably a hashed list.  A hashed list, however, will not do
  1183.         much for you if you regularly want to access the next item,
  1184.         first item in the list, or last item, such as in a list browsing
  1185.         system.  Hashed lists have no logical beginning or end, and for
  1186.         this reason, there is no such thing as a "first item" or "next
  1187.         item" in a hashed list.  Each entry is a single entity,
  1188.         retrievable only as a single entity, with no relation to any
  1189.         other entry in the hashed list.  This excludes applications that
  1190.         require browsing, as I have mentioned, but is perfect for symbol
  1191.         tables, dictionaries, and the like.
  1192.  
  1193. Q3.2    This is all pretty new to me.  Give me a practical review.
  1194.  
  1195.  
  1196. A3.2    Okay.  In the hashed list there is no sense of sequence in the
  1197.         classic sense of the concept.  Items are put into buckets based
  1198.         upon the type of calculation I have already discussed, and if
  1199.         the bucket is already in use, a new bucket is found according to
  1200.         a set system. Therefore, two similar items in a hashed table may
  1201.         actually have a physical distance of 500 entries between them.
  1202.  
  1203.         A practical example:
  1204.  
  1205.         We have a hash table 7 buckets big, and you want to store three
  1206.         entries in it, using hashing.  For simplicity, let's just store
  1207.         the characters A, B, and C, using their ASCII values as keys.
  1208.         Their buckets would be:
  1209.  
  1210.         Item   Formula    Bucket
  1211.         =========================
  1212.           A    65 MOD 7     2
  1213.           B    66 MOD 7     3
  1214.           C    67 MOD 7     4
  1215.  
  1216.         No collisions have occured here, since this is a simple case.
  1217.         Now, let us add just one more item: H.  The first bucket that
  1218.         H will request is 72 MOD 2, or 2, which is being used by A.
  1219.         This is collision.  Now, we must find an empty bucket, and so,
  1220.         we apply a common method to the old bucket: we subtract an
  1221.         offset from 2.  The offset is calulated thus:
  1222.  
  1223.                 Offset = TableSize - Bucket, or
  1224.                 Offset = 7 -2
  1225.                 Offset = 5
  1226.  
  1227.         Okay, now, whenever a collision occurs, we recalculate a
  1228.         position using this formula:
  1229.  
  1230.                 NewPos = OldPos - Offset
  1231.                 NewPos = 2 - 5
  1232.                 NewPos = -3
  1233.  
  1234.         In cases where NewPos is less than 0, we then add the table size
  1235.         to the interim result:
  1236.  
  1237.                 NewPos = NewPos + TableSize, or
  1238.                 NewPos = -3 + 7
  1239.                 NewPos = 4
  1240.  
  1241.         We see that this new bucket, 4, is being used by C, and so we
  1242.         have to recalculate the bucket one more time:
  1243.  
  1244.                 NewPos = OldPos - Offset, or
  1245.                 NewPos = 4 - 5
  1246.                 NewPos = -1
  1247.  
  1248.                 NewPos <0 so
  1249.                 NewPos = NewPos + TableSize, or
  1250.                 NewPos = -1 + 7
  1251.                 NewPos = 6
  1252.  
  1253.         We see that 6 is an empty bucket, and therefore, our table now
  1254.         looks something like this:
  1255.  
  1256.  
  1257.         Entry   Bucket
  1258.         ==============
  1259.                   1 (empty bucket)
  1260.          A        2 (no collisions)
  1261.          B        3 (no collisions)
  1262.          C        4 (no collisions)
  1263.                   5 (empty bucket)
  1264.          H        6 (arrived at after two collisions)
  1265.                   7 (empty bucket)
  1266.  
  1267.         Now, remember from past explanations that searches are conducted
  1268.         by comparing each entry to the key until an empty bucket is
  1269.         reached. Therefore, to find A in the table, we calculate a
  1270.         bucket of 65 MOD 7, or 2.  We look in bucket 2, and see that our
  1271.         key of A is the same as the table entry A.  We have therefore
  1272.         found our entry in one look!  Now, let's look for I.  That's a
  1273.         bit different, since it isn't in the list.  How many looks are
  1274.         needed to tell us that it isn't?  Well 73 MOD 7 is 3, and we see
  1275.         immediately that bucket 3 is a B, not an I.  We recalculate the
  1276.         next bucket, and get:
  1277.  
  1278.                 Offset = 4
  1279.                 NewPos = (3 - 4) or -1
  1280.                 Less than 0, so
  1281.                 NewPos = 6
  1282.  
  1283.         Bucket 6 is occupied by an H, and so we calculate the next bucket:
  1284.  
  1285.                 Offset = 4
  1286.                 NewPos = (6-4) = 2
  1287.  
  1288.         Bucket 2 is occupied by an A, and so:
  1289.  
  1290.                 NewPos = (2 - 4)
  1291.                 NewPos = -2 + 7 = 5
  1292.  
  1293.         Finally, bucket 5 is empty.  Therefore, since we've arrived at
  1294.         an empty bucket BEFORE arriving at I, we can say that I is not
  1295.         in the list.  How many steps required?  Four.  Quite a bit of
  1296.         overhead on a short list of 7 entries, but consider a list of
  1297.         100,000 entries!  Four searches to find an item is fast!
  1298.  
  1299. Q3.3    Okay, how about a real working example of hashing in QuickBASIC?
  1300.         Theory is fine for CompSci freaks, but I'm a coffee and pizza
  1301.         programmer, not an egghead.
  1302.  
  1303. A3.3    I mentioned that one perfect use of hashing is for word
  1304.         distribution counters.  Here is one from Rich Geldreich that has
  1305.         been tweaked by me to account for some things that Rich did not
  1306.         know then about hashing table sizes.
  1307.  
  1308. S5.0    WORDHASH.BAS [F210S05.BAS]
  1309.  
  1310. 'WORDHASH.BAS v1.10 By Rich Geldreich 1992
  1311. '
  1312. 'Uses hashing to quickly tally up the frequency of all of the words in a
  1313. 'text file. (This program assumes that words are seperated by either tab
  1314. 'or space characters. Also, all words are converted to uppercase before
  1315. 'the search.)
  1316. '
  1317.  
  1318. DEFINT A-Z
  1319. DECLARE SUB Show.Counts ()
  1320. DECLARE SUB Process.Line (A$)
  1321. DECLARE SUB UpdateFreq (A$, KeyIndex)
  1322. CONST TRUE = -1, FALSE = 0
  1323.  
  1324. DIM SHARED TableSize
  1325.  
  1326. Main:
  1327.  FileName$ = COMMAND$
  1328.  CLS
  1329.  LOCATE 1, 1
  1330.  PRINT "WORDHASH.BAS By Rich Geldreich 1992"
  1331.  OPEN FileName$ FOR INPUT AS #1 LEN = 16384
  1332.  
  1333. ' In Rich's original version, the TableSize was set at 7000.  My version
  1334. ' guesses at how large the table needs to be based on this:
  1335.  
  1336. ' There are 5.5 characters in the average word.  Therefore, divide the
  1337. ' text file length by 5.5.  For safety, assume that as many as
  1338. ' half of those will be unique.  In normal text, half the words are in the
  1339. ' hundred most common list, so this plays it pretty safe!  It will die
  1340. ' if you take a file that is over about 50% unique words, however!  This
  1341. ' is for NORMAL text files, not word dictionaries, where all entries are
  1342. ' unique!
  1343. '
  1344. 'SPLICE IN FROM EARLIER SAMPLE 4.0 IN THIS FAQ
  1345. '           VVVVVVVVVVVVV
  1346. TableSize = funFirstPrime(LOF(1) * .09)
  1347. REDIM SHARED WordTable$(TableSize)
  1348. REDIM SHARED Counts(TableSize)
  1349. DIM SHARED New.Words
  1350.  
  1351.  DO UNTIL EOF(1)
  1352.      LINE INPUT #1, A$
  1353.      Process.Line A$
  1354.      N = N + 1
  1355.      LOCATE 3, 1: PRINT N; "lines processed,"; New.Words; "words found"
  1356.  LOOP
  1357.  
  1358. SUB Process.Line (A$)
  1359.  
  1360.     ASEG = SSEG(A$) 'QuickBASIC 4.5 users change this to VARSEG(A$)
  1361.     AOFS& = SADD(A$)
  1362.     DEF SEG = ASEG + AOFS& \ 16
  1363.  
  1364.     AAddress = AOFS& AND 15
  1365.     Astart = AAddress
  1366.     AEndAddress = AAddress + LEN(A$)
  1367.  
  1368.     'get a word
  1369.     GOSUB GetAWord
  1370.     'update the frequency of the word until there aren't any words left
  1371.     DO WHILE Word$ <> ""
  1372.         UpdateFreq Word$, KeyIndex
  1373.         GOSUB GetAWord
  1374.     LOOP
  1375.  
  1376.     EXIT SUB
  1377.  
  1378. GetAWord:
  1379.     Word$ = ""
  1380.  
  1381.     'find a character
  1382.     P = PEEK(AAddress)
  1383.     DO WHILE (P = 32 OR P = 9) AND AAddress <> AEndAddress
  1384.         AAddress = AAddress + 1
  1385.         P = PEEK(AAddress)
  1386.     LOOP
  1387.  
  1388.     'if not at end of string then find a space
  1389.     IF AAddress <> AEndAddress THEN
  1390.         KeyIndex = 0
  1391.         GOSUB UpdateKeyIndex
  1392.  
  1393.         'remember where the character started
  1394.         WordStart = AAddress
  1395.  
  1396.         AAddress = AAddress + 1
  1397.         P = PEEK(AAddress)
  1398.         GOSUB UpdateKeyIndex
  1399.         'find the leading space
  1400.         DO UNTIL (P = 32 OR P = 9) OR AAddress = AEndAddress
  1401.             AAddress = AAddress + 1
  1402.             P = PEEK(AAddress)
  1403.             GOSUB UpdateKeyIndex
  1404.         LOOP
  1405.         KeyIndex = KeyIndex - L
  1406.  
  1407.         'make the word
  1408.    Word$ = UCASE$(MID$(A$, WordStart - Astart + 1, AAddress - WordStart))
  1409.  
  1410.     END IF
  1411. RETURN
  1412.  
  1413. UpdateKeyIndex:
  1414.     IF P >= 97 AND P <= 122 THEN
  1415.         L = P - 32
  1416.         KeyIndex = KeyIndex + L
  1417.     ELSE
  1418.         L = P
  1419.         KeyIndex = KeyIndex + L
  1420.     END IF
  1421. RETURN
  1422.  
  1423. END SUB
  1424.  
  1425. SUB UpdateFreq (A$, KeyIndex)
  1426. STATIC collisions
  1427.     'adjust the keyindex so its within the table
  1428.     KeyIndex = KeyIndex MOD TableSize
  1429.     'calculate an offset for retries
  1430.     IF KeyIndex = 0 THEN
  1431.         Offset = 1
  1432.     ELSE
  1433.         Offset = TableSize - KeyIndex
  1434.     END IF
  1435.     'main loop of hashing
  1436.     DO
  1437.         'is this entry empty?
  1438.         IF WordTable$(KeyIndex) = "" THEN
  1439.             'add this entry to the hash table
  1440.             WordTable$(KeyIndex) = A$
  1441.             New.Words = New.Words + 1
  1442.             IF New.Words = TableSize THEN
  1443.                 BEEP
  1444.                 PRINT : PRINT "Not enough room in word table!"
  1445.                 END
  1446.             END IF
  1447.             EXIT SUB
  1448.         'is this what we're looking for?
  1449.         ELSEIF WordTable$(KeyIndex) = A$ THEN
  1450.             'increment the frequency of the entry
  1451.             Counts(KeyIndex) = Counts(KeyIndex) + 1
  1452.             EXIT SUB
  1453.         'this entry contains a string other than what we're looking for:
  1454.         'adjust the KeyIndex and try again
  1455.         ELSE
  1456.             collisions = collisions + 1
  1457.             LOCATE 5, 1: PRINT "Collisions: "; collisions
  1458.             KeyIndex = KeyIndex - Offset
  1459.             'wrap back the keyindex if it's <0
  1460.             IF KeyIndex < 0 THEN
  1461.                 KeyIndex = KeyIndex + TableSize
  1462.             END IF
  1463.         END IF
  1464.     LOOP
  1465.  
  1466. END SUB
  1467.  
  1468. =======>8 SAMPLE 5.0 ENDS HERE 8<=========
  1469.  
  1470.                           END OF QUIK_BAS FAQ2.1
  1471.  
  1472. '
  1473.  
  1474.  
  1475.  
  1476. Msg #:  8968                      QUIKBAS Subboard
  1477.  From:  JOE NEGRON                Sent: 03-27-93 10:38
  1478.    To:  JIM COYLE                 Rcvd: -NO-
  1479.    Re:  BLAH.
  1480.  
  1481. JC> Does anyone have a Date2Int function that could be posted? Thanks.
  1482.  
  1483. Ask and ye shall receive...
  1484.  
  1485. ============================== Begin code
  1486. ==============================
  1487. DEFINT A-Z
  1488.  
  1489. DECLARE FUNCTION Date2Day% (DateX$)
  1490. DECLARE FUNCTION Date2Mth% (DateX$)
  1491. DECLARE FUNCTION Date2Serial& (DateX$)
  1492. DECLARE FUNCTION Date2Year% (DateX$)
  1493.  
  1494. '**********************************************************************
  1495.  
  1496. '* FUNCTION Date2Day%
  1497. '*
  1498. '* PURPOSE
  1499. '*    Returns the day number given a date in the standard date format.
  1500. '**********************************************************************
  1501.  
  1502. FUNCTION Date2Day% (DateX$) STATIC
  1503.    Date2Day% = VAL(MID$(DateX$, 4))
  1504. END FUNCTION
  1505.  
  1506. '**********************************************************************
  1507.  
  1508. '* FUNCTION Date2Mth%
  1509. '*
  1510. '* PURPOSE
  1511. '*    Returns the month number given a date in the standard date
  1512. format.
  1513. '**********************************************************************
  1514.  
  1515. FUNCTION Date2Mth% (DateX$) STATIC
  1516.    Date2Mth% = VAL(DateX$)
  1517. END FUNCTION
  1518.  
  1519. '**********************************************************************
  1520.  
  1521. '* FUNCTION Date2Serial&
  1522. '*
  1523. '* PURPOSE
  1524. '*    Returns the astronomical Julian day number given a date in the
  1525. '*    standard date format.  Note that the year must be 1583 or
  1526. greater.
  1527. '*
  1528. '* INTERNAL ROUTINE(S)
  1529. '*    FUNCTION Date2Day% (DateX$)
  1530. '*    FUNCTION Date2Mth% (DateX$)
  1531. '*    FUNCTION Date2Year% (DateX$)
  1532. '**********************************************************************
  1533.  
  1534. FUNCTION Date2Serial& (DateX$) STATIC
  1535.    Month% = Date2Mth%(DateX$)
  1536.    Day% = Date2Day%(DateX$)
  1537.    Year% = Date2Year%(DateX$)
  1538.  
  1539.    IF Month% > 2 THEN
  1540.       Month% = Month% - 3
  1541.    ELSE
  1542.       Month% = Month% + 9
  1543.       Year% = Year% - 1
  1544.    END IF
  1545.  
  1546.    TA& = 146097 * (Year% \ 100) \ 4
  1547.    TB& = 1461& * (Year% MOD 100) \ 4
  1548.    TC& = (153 * Month% + 2) \ 5 + Day% + 1721119
  1549.    Date2Serial& = TA& + TB& + TC&
  1550. END FUNCTION
  1551.  
  1552. '**********************************************************************
  1553.  
  1554. '* FUNCTION Date2Year%
  1555. '*
  1556. '* PURPOSE
  1557. '*    Returns the year number given a date in the standard date format.
  1558. '**********************************************************************
  1559.  
  1560. FUNCTION Date2Year% (DateX$) STATIC
  1561.    Date2Year% = VAL(MID$(DateX$, 7))
  1562. END FUNCTION
  1563.  
  1564. '
  1565.  
  1566.  
  1567. Msg #:  9012                      QUIKBAS Subboard
  1568.  From:  GEOFFREY LIU              Sent: 03-29-93 17:53
  1569.    To:  JOEL YEN                  Rcvd: -NO-
  1570.    Re:  DISABLE THE PAUSE KEY
  1571.  
  1572. JY>        Hello! Do anyone know how to disable the PAUSE function of the
  1573. JY>keyboard? Please leave a message to me. Thanks a lot.
  1574.  
  1575.         The following routine doesn't really disable the pause button,
  1576. but turns it off 18.2 times every second.
  1577.  
  1578. 'Stardate: 02-01-93
  1579. 'From: EDWARD LAM                     
  1580. 'Conf: NANET-BASIC (44)
  1581.  
  1582. '   Because B_OnExit might have too many routines registered already, I've made
  1583. 'NoPause a function returning TRUE(-1) if everything is ok, otherwise FALSE(0).
  1584. '   The B_OnExit routine does look a little eratic to me in the environment but
  1585. 'try it and see what happens.
  1586.  
  1587. 'cut here for NOPDEMO2.BAS
  1588.  
  1589. 'Example program for NoPause2 module.
  1590. '
  1591. DECLARE FUNCTION NoPause%
  1592. '
  1593. CLS
  1594. PRINT "Press N for NoPause, U to Unhook NoPause, ESC to exit"
  1595. DO
  1596.   I = (I + 1) MOD 1000
  1597.   LOCATE 5, 5: PRINT "     ";
  1598.   LOCATE 5, 5: PRINT I;
  1599.   A$ = UCASE$(INKEY$)
  1600.   IF A$ = "N" THEN
  1601.      IF NOT NoPause% THEN   'We call NoPause here
  1602.         LOCATE 2, 1
  1603.         PRINT "B_OnExit Full!  Can't stop pause key"
  1604.      END IF
  1605.   END IF
  1606.   IF A$ = "U" THEN
  1607.       CALL UnhookNoPause  'Have option to disable nopause from
  1608.                            'within program
  1609.       LOCATE 2, 1
  1610.       PRINT SPACE$(36)
  1611.   END IF
  1612. LOOP UNTIL A$ = CHR$(27)
  1613. 'Note that we don't care the state of the vectors since B_OnExit will call
  1614. 'UnHookNoPause for us.  You can call UnHookExit as many times as you like
  1615.  
  1616.  ;NoPause2.ASM
  1617.  
  1618. ;Note that this file has been modified so that the UnHookNoPause routine
  1619. ;does not need ever (or should it) to be called.  --EKL
  1620.  
  1621. EXTRN   B_OnExit:FAR            ;QB's internal routine calls all clean
  1622.                                 ;up routines registered with it ony
  1623. _any_ exit
  1624.  
  1625. ;
  1626. ; NoPause.ASM by Brent Ashley  /  NoPause2.ASM modified by Edward Lam 01/31/93
  1627. ;
  1628. .model medium, basic
  1629. .code
  1630. Old1C        Label Dword          ;Label for to old Int 1Ch
  1631. Old1COffset  dw ?                 ;Offset part
  1632. Old1CSegment dw ?                 ;Segment part
  1633. Hooked       db 0                 ;Our installed flag
  1634.  
  1635. ;Note that if an error occurs registering NoHookPause, NoPause will return
  1636. ;FALSE.  Right, it's a function now instead of a sub -- EKL
  1637. NoPause proc uses ds dx           ;From BASIC: Ok% = NoPause%
  1638.                                   ;Use UnhookNoPause to disable NoPause
  1639.  
  1640.         cmp cs:Hooked,0           ;Are we already hooked?
  1641.         jnz InstallExit           ;If so, exit
  1642.  
  1643.         ;following section just cut&paste from EVENTCHN.ASM by Jim Mack
  1644.         mov     dx, offset UnHookNoPause
  1645.         push    cs                ; push far address of UnHookNoPause
  1646.         push    dx                ; to register the exit routine
  1647.         call    B_OnExit          ; so that we don't hang machine
  1648.         or      ax, ax            ; registered OK?
  1649.         jz      ErrorExit         ; error: too many registered routines
  1650.  
  1651.         mov ax,351Ch              ;Get current vector for int 09h
  1652.         int 21h
  1653.  
  1654.         mov cs:Old1CSegment,es    ;Remember it for later
  1655.         mov cs:Old1COffset,bx
  1656.         mov ax,251Ch
  1657.         push ds
  1658.         push cs
  1659.         pop ds                    ;Point int 1Ch to our code
  1660.         mov dx, offset OurInt1C
  1661.         int 21h
  1662.         pop ds
  1663.         mov cs:Hooked,-1          ;Set our installed flag
  1664.         mov ax, -1                ;return TRUE for ok
  1665.         jmp InstallExit
  1666.  
  1667. ErrorExit:
  1668.         sub ax, ax                ;put 0 into ax to return with error
  1669.  
  1670. InstallExit:
  1671.         ret
  1672.  
  1673. OurInt1C:                         ;Our Int 1Ch handler
  1674.         push ds                   ;
  1675.         push bx
  1676.         push ax
  1677.         xor bx, bx                ;point DS to BIOS data area
  1678.         mov ds, bx                ;
  1679.         mov bx, 0418h
  1680.         mov al, [bx]
  1681.         and al, 0F7h              ;reset nopause flag
  1682.         mov [bx], al
  1683.         pop ax
  1684.         pop bx
  1685.         pop ds
  1686.         jmp dword ptr cs:[Old1C]  ;Transfer to orig Int 1Ch
  1687.  
  1688. NoPause endp
  1689.  
  1690. UnhookNoPause proc                ; from BASIC: CALL UnHookNoPause
  1691.         cmp cs:Hooked,0           ; are we installed?
  1692.         jz UnHooked               ; nope - exit
  1693.  
  1694.         push ax
  1695.         push ds
  1696.         mov ax,251Ch              ;Unhook ourself
  1697.         mov ds,Old1CSegment
  1698.         mov dx,Old1COffset
  1699.         int 21h                   ;Point Int 1Ch back to original
  1700.         pop ds
  1701.         pop ax
  1702.         mov cs:Hooked,0           ;Set installed flag back to zero
  1703.  
  1704. UnHooked:
  1705.         ret
  1706. UnhookNoPause endp
  1707.  
  1708. END
  1709. '
  1710.  
  1711.  
  1712. Msg #:  407                       QUIKBAS Subboard
  1713.  From:  CALVIN FRENCH             Sent: 04-02-93 18:31
  1714.    To:  EARL MONTGOMERY           Rcvd: -NO-
  1715.    Re:  256 COLORS
  1716.  
  1717.  
  1718. Er, um, I'd have to disagree with you on that one. Ok, here look  
  1719. at this chunk of code I whipped up a little while ago -- Maybe  
  1720. it will help! Oh, yes, thank you very much for the code, because 
  1721.  
  1722. now I can write the Palette vals. directly, which should help me  
  1723. greatly -- it's much faster, as you'll see: 
  1724. -------------------------------------------------------------
  1725. '--- FADEON.BAS 
  1726. 'An example of how to sucessfully fade on and fade off different color 
  1727. 'values based on different color values. 
  1728. 'Released by Calvin French to the Public Domain. 
  1729. 'For the discretion of all QuickBASIC users and anyone else. Please feel
  1730. 'free to distribute this file anyway you like and make a buck if you can!
  1731. '----------------------------------------------------------------------
  1732.  
  1733.  
  1734. DEFINT A-Z 
  1735. DECLARE SUB Fade (text$, red, blue, green) 
  1736.  
  1737. SCREEN 12        'works ok in screen 13 too! 
  1738.  
  1739. starting: 
  1740. DO 
  1741. LOCATE 2, 1 
  1742. COLOR 10 
  1743. INPUT "Text To Fade?", text$ 
  1744. INPUT "Red Level?", red 
  1745. IF red > 63 OR red < 0 THEN GOTO DontDoThat 
  1746. INPUT "Green Level?", green 
  1747. IF green > 63 OR blue < 0 THEN GOTO DontDoThat 
  1748. INPUT "Blue Level?", blue 
  1749. IF blue > 63 OR blue < 0 THEN GOTO DontDoThat 
  1750. Fade text$, red, blue, green 
  1751. LOOP WHILE text$ <> "" 
  1752. END 
  1753.  
  1754. DontDoThat: 
  1755. CLS 
  1756. LOCATE 1, 1 
  1757. COLOR 4 
  1758. PRINT "Valid Numbers Between 0 and 62" 
  1759. GOTO starting 
  1760.  
  1761. SUB Fade (text$, red, blue, green) 
  1762. bluestep! = blue / 63 
  1763. greenstep! = green / 63 
  1764. redstep! = red / 63 
  1765.  
  1766. LOCATE 10, 10 
  1767. COLOR 1 
  1768. PRINT text$ 
  1769. FOR i = 0 TO 63 STEP 1 
  1770.      PALETTE 1, (blue * 65536) + (green * 256) + red 
  1771.      bluetemp! = bluetemp! + bluestep! 
  1772.      greentemp! = greentemp! + greenstep! 
  1773.      redtemp! = redtemp! + redstep! 
  1774.      blue = bluetemp! 
  1775.      green = greentemp! 
  1776.      red = redtemp! 
  1777.      NEXT i 
  1778. FOR i = 63 TO 0 STEP -1 
  1779.      PALETTE 1, (blue * 65536) + (green * 256) + red 
  1780.      bluetemp! = bluetemp! - bluestep! 
  1781.      greentemp! = greentemp! - greenstep! 
  1782.      redtemp! = redtemp! - redstep! 
  1783.      blue = bluetemp! 
  1784.      green = greentemp! 
  1785.      red = redtemp! 
  1786.      NEXT i 
  1787.  
  1788. COLOR 15 
  1789. END SUB 
  1790.  
  1791.  
  1792. -------------------------------------------------------------
  1793.  
  1794. Umm maybe that will help you, regardless, the method of changingthe
  1795. palette vals using PALETTE is equal to:
  1796.  
  1797. PALETTE ColorVal, (Blue * 65536) + (Green * 256) + Red 
  1798.  
  1799. That is the formula, if I remember correctly! Well, hope that helps out,
  1800. '
  1801.  
  1802.  
  1803. Msg #:  536                       QUIKBAS Subboard
  1804.  From:  JOHN GALLAS               Sent: 04-03-93 16:45
  1805.    To:  ALL                       Rcvd: -NO-
  1806.    Re:  ELIZA.BAS     1/3
  1807.  
  1808. Heres a PostIt! script for an eliza artificial intelligence program.  I
  1809. would've addressed it to the person who was asking for one, but I can't
  1810. remember his name!  So anyways, here it is..
  1811.  
  1812. 'Save this script to a file, edit out all of the non-QB related text and
  1813. 'execute it in a QB environment to retrieve ELIZA2.LZH.
  1814. DEFINT A-Z:DIM SHARED A(685)AS STRING*63,I,T$:FOR A=0 TO 6:P(A)=2^A
  1815. NEXT:T$="abcdefghijklmnopqrstuvwxyz":T$=T$+UCASE$(T$)+"0123456789()"
  1816. G"qIuylSHwnTK7caaGKzaaaekwZsasajuetjPvqUq0tdPlrnbaaiSmDAATruh32KPA
  1817. G"fL(3tSyifehK006ILqqQni5M4TnjlolXZw4kzWU7oBC3mADf)X)Vx2AkP4COuLSu
  1818. G"5cHV)GDYAJ2ycdynd)Z(ld4(ZCTTxNA1to9Ilmp(kN)p98Noh6)ftyEZl13vR2Au
  1819. G"YxBwRvR26wzdlkONA7APWng1AdUYP5MTxTtfNkNT6O5gEflKfB4DxjUnLbSTn2QH
  1820. G"wfBZdtXAzRoyRix6zcABRQt92FvadSX(BlIslBq)CzBwX3f7VRUI07QkuDhxyr)j
  1821. G"OUUPs9(93JIx61bDUDAJDqvE5NCVEyQTUgoxvA1Yk1QIr(T3MHaU7vnWpVyaR61r
  1822. G"WZUR9FMT05(gKydmw1ZLPQHR3qxkme2watJJlfmN7SUcJ26vDZG30wD06tzTHD22
  1823. G"zJIEvv6Gy9JkgQqZw2k7(vKzyD)XE0AG3uhBSuGt1QyTpgB1mQJL3RRDgwlrzI4u
  1824. G"pXfM7yFC8dFeADwDwlbYYspd3Q7v4k()n0SMjRBPnATrQJsvXgcCYImmP2MVhOot
  1825. G"x6cq9vLXORbI4Gl2Tvf1q6CjxziIseMsz(IlmMLQv37fslATcspTGpBsp6DBiCrl
  1826. G"31Wl1uNwRDYH7e5d(wNA3CGYD7iYmgvzBocyVLa)EZYRo(nuwpDbn0V9GcMDb9j0
  1827. G"0b(1RlQKWnUDuV8qCmL7tp)gia9nfd52MBdZRdARTzDV7OincRSg9p2F9Ilz54qW
  1828. G"kd(RzLxwRd)wTGCt2P0ZvjSdLFY3AdMwvUTnJs)bfxcJM43kTVIesAbz5LPDASPE
  1829. G"ROvZcE2riXNWedftANrnNiJtzKGvcGIV8bPYr93vfPIeWnuIeho(UGIlPEBn1qtz
  1830. G"lCKunJIFmnR)OFedKe451MqcysO1Y0g2u416(cuePWihPP2AqsPZRbTgkOxb7IpS
  1831. G"gq6sDiHvO715hdKJN1cmy95iinp6TVCN(CKNuAoHsiNtThFe5k25wYw9a9lVffCu
  1832. G"WEgwqUuTFDPG9L3(ZnltUUD9StQCh2fG)1tUvA5qKFN)IugHn7LAkO5inmrTDPtd
  1833. G"Qig2vtkKQGDDoe7YkSxNvTNXJ2vYFVQelR58x1CaTCmsRNIcETY57csqyvyGaawk
  1834. G"Tr(F56i)MNPfRP7WvF(e)jfM9oLepQOv7BnSuRRmmSDXKLgVt2zfCqv5e1Vt56gZ
  1835. G"1kLsk8ib9hNM8t1gKOkUUK5zw)pbAssxG9RbkWExRroKpCD4rYv0AoORXtJKwRKP
  1836. G"6vP6zT31KRi13WEeJMsBMY)e50fxb2HyxEUhH)xbKdPuoG3JpwNfs)fdQjbfeZWC
  1837. G"uCn3rtBhLuLvwoyuT4zlnwxF)2u3TsCV(R6fR1MGV9n3bD3Y1F9dX(NvOQleek4y
  1838. G"4cKEGhHSD24F4j)dl)t62wgMsPMBaffaPK3F70IP)FWW(pdkIFIaOhseVgOvIPfC
  1839. G"zAd0MyqDyVF6gAIR5SVlUIhxUX2iD7YlAH5TUNKpTyXHIWd05JTgRSMPzP9gf5hq
  1840. G"CnVsFjsMruXiMURX8ITS2fBeU8cucDqayomA6t944rEuDGpaw0O1X8H2VI1EJG4H
  1841. G"FUkM9bKTs61Dc3oFJp1cTnR1GL4(KEzzF(uJwT5VTe(2Wp9T4y2wA(CDJbV99BzI
  1842. G"erBOWKjfFI5TxkcL9fHOQsV7r9qJ9LViAjno)rtTaHRr(aNAXgFQ3fdvkJk4Usqn
  1843. G"ItJirinrDzCXBQDqqJvxWwIEynpz162vakB7Sm6wXu8gnGJq4JTpIvOEP611kh7e
  1844. G"BWRj4nx8izbslJ2qBIHEai6eEK0a65g4m7C2wod9La8WPqdQ6gcXhEfITqHnnZF6
  1845. G"fdqpiehZL8Pw3QC6vyK)beuxewldMXp(e78RaLYUh52oA41QzXAL6yo3kQwKmqRT
  1846. G"sw83fOzoGRie9B77LaJIpm4ldsGxtD0rmbItSrsmo1j(4v6qLEQ6aaxakfqsemur
  1847. G"zaVpIH(7ckaLKIm7CLHo)(st7ZRqNfbMqOMOiSpRMu460RVFPEb48GbSvwHws4Mw
  1848. G"NyMYT5g0SlIDfmcDhKEViF8gVJYrlRt2neNIAsqjmpa8YfdJjplkzKAzDLfnndPd
  1849. G"ClRk17nKCSGbmq4VSySK20RJOY6lI39Q08Q(LpqcbBFaBUtjsLNOvU72Zhpy3qjy
  1850. G"OhdiWI)sayhXofnKhhas913z90vPCJStdmg21zj8Dkl8v4IBCU06DLuevJJuq5vO
  1851. G"Na6nqSOj7i7ukNu9)p0t7)I2b)bXBf8et703KmVoYOOvevlLU1jrVQ04jIsrqq9e
  1852. G"8lPLlNUS5YJmIiAZDh)WcgBevDgsIe3t8prCBInCKw4vSLQ7IvVk2QVsE)6BxD8h
  1853. G"6dblnXrzokrYwfLXoZAEWUiAWJx)YtOTbgvt275RxxgJm)E2v7NQE1Xg2YGo1zZA
  1854. G"HZxhoC5ShUSVfw3()VK5QpLiD0D)(ZtcPii8W9nlPE9kxzMMKGig1W4Fx93S8)ri
  1855. G"RL)97j)9ECi7AaXMBGw42sw)sUv2jODkHyEy2HTLGh66jzL1gVH74ECA7b(KmOuo
  1856. G"RDgPnqsBCHT5PRo6nl3D1XN(5BwydocMFutDmY2EIy2woFvbPFZKeXqPIMSw(yq4
  1857. G"iRm7fYnldc(eFXffulOGh)AnWF4n05NfYvNLZGrxsu31oPnmIkgkQcqa6td)tqcG
  1858. G"LkFdr1llgIpjvuqXQpYImouQaJRtlbyMwKl3f4u8x8kErUactbBs5JSzl3k2ArLh
  1859. G"vcbcPwuXoNuYJXWX7nDssXZ6WewGJGa7XivNDLiA6gjyHs2e5Cwa1vPDLE1(Cpw3
  1860. G"c5P59kXOPVJ4llJBJGrf49URx8fqawBBPzkCHaCZGSy(XUi5cU5Obv7N)uKfgNeO
  1861. G"QG7yVeKkayb(Vk0jn01KKV3jXQBbrwAtiqgovmFirb8jtWsupczmltpYIdbcR8sC
  1862. G"(7uGinoDs2rxYkws7IvbH5kmzz2J1uWvaofTqI9pdEtS4DGssfUTvkydeo2cAkIG
  1863. G"eyMsSzC2yl8wjXU(AYM470eOyer4sjsuw18TdAGjDk9WNmV3DtwDPcNasQitbuHU
  1864. G"1tKgQE9iu93Gp5uwt9BYqmDC7MR594waGnY1vS30h6NG6sNiBauxCgXXBJp9MZ(5
  1865. G"wVZ(JDKjgL8IBdGLmcknVHMcEyVI6wWra0A0ZKtIpo4xmHoz0T6GiSOymh45BYdu
  1866. G"fdiAE8nFnQq0MHQVG0iEXN)DRW6MRXz1)U(7)(h1AEDSu3APItko)q41QC8sycxk
  1867. G"28IVZSCGeyGDSCb1HyXSDWR7Ikv0xGMyVjYBgAazIKMlhdmnyqnsxSycehNWOgE6
  1868. G"XTjwJsFWfzZ4esPupnTvgevS83Qy5bTajIZp6N1Nv(RTr0uQ3RokWchaicPNbOjF
  1869. G"BfxoH6s7aFKeZVBxOkrb(B6zq0dhWd8HVdhkGV9wiigqS5Jd89lYWqKzieuKqjeJ
  1870. G"OlBSbhJD0YeNKlx7kwzJoZyRItyFSYQYUzTR)TWgKX4O1IoGqIk)T6lpXdEEHWP2
  1871. G"oR62bUQckgUiXAxed4KHihWY1ZmwVDDU9WPNpRsduDmW0YsYwp(hU)topagwtemo
  1872. G"4sePgXVYCzSqYt5ZlhdpH61fRhjLsEIEMjeTdy7T(4NBiX1ut6ZKtkbfG(O1HxKw
  1873. G"C8RyH8xwakBmJywk8kGmzKYx3cNy)VhymkmHfODbk)gLUe4wgAGrpnfQP0NyPONb
  1874. G"1SEc4OHUezFBVqIg2g9F0y(Xf2k2mzWLYjfOznKnkuvtZTDitBYuD4kKOP8r0jQX
  1875. G"eW5ojoZjsqpnPnFuswloJ41QPwbkyjzFFV6isrZhjawwCLNkowLy35VnRAcvGDrR
  1876. G"klslTc(JwZfjhd5mNkFmWY)WS0NLd3YXJlzC)PfSSZ(9IvYhV)b3X5nAWyPR4GHN
  1877. G"A5iA04DUZMZU6QIYMC7aLCijfjLKBW0(n88CN5cFfMHIW5lJmx(xRS4tMK2WunK)
  1878. G"TuRcTYebYk6yIceii5my))39arbh7JBEZB)5s5IAja5fG0NQUwsdN89iz2X99HsW
  1879. G"pyqX1FU8Z4CgDATtZCymDl(vf4Efin6E0toIjahy3RaoxcYjc2BUhOYtqNltXVk9
  1880. G"4D8XFpoA14R3pV8SfqicQTWgA10I2jaaaaWbaay)IDAfibKqrmLKwb5crbrfz71e
  1881. G"xaaCqc7zx14A(D87vami9tjHgeSfm(uifvgsW2pPb2A)uZNKBU4f5(UxVjEZJKnn
  1882. G"9csEzWltq5L7oC3S2iTLRDwTFfAPDE52pV8jNR3mp6uEYxwuZEwr)mzDEq1vxRjU
  1883. G"X8qBmXxj7nx5NtU6VEg64PsVSwRLEPDPlK12q2)ymm)HALAQnkeRzLnDmP1mJXVF
  1884. G"FE6NvOLFE5V0QpuU0p(PLP8QPTK70T)uRUv5LmYQdVXc3)XeJtfpFWOM(JYZAzfY
  1885. G"rTI0lBruG90jMQ8BVBUwz9knpIgk5VF(5LtrF6KsAp2Ql1ltxZwIEYg0aNXyUDmj
  1886. G"8h0GnYuZSM)YZWTSSng2Q9QTF16mPZm3SuSKHjyE7iKPn6oqiD4WzwiTspH(wTyN
  1887. G"JRnQ0bQ)AEd7mEgPhGDnCbtc7gJFU2y1(rhJQ6yt8PQ)5(3xFZFvwGDxrASCQcp3
  1888. G"7SBiMQKwwCRYS9SrHmLi1Ig9TI1boET1ZwLIjHXopU1yxdrQrICS9VelUf9RIGcc
  1889. G"inar8L9rS5cT0gDtsrKDZSQklSqxvtYEFyTbFH(6BVzPblUeSSQMvSppN(gCBDop
  1890. G"FltKqt4OVpHh6tXLy)AYrLoHKkg)nRbX(VIJUNbtB9E9ZCXyBhPq8HU(lo6jdYQ5
  1891. G"0O)lsxtS2FOSRVPWIjYMeMDDH0QLrAtoqBcBaNt1JTr4cZa63dpgfyOCGnNKmzEZ
  1892. G"kkErsVQYO977ToSgU1vn3G)(yPe4OX0)gVR4)1V()VKvULc1xy)Go0Bl0clRzi8A
  1893. G"A9)w7eQpVmdhkLJLkzRJWophJQ)0jpHqaZl9nDV)gwohr(Fs7b6Xwms)xbGCJ95F
  1894. G"BDulw8SnF2V)kNfoZkiZCpaILprCqDWPyb0CD3f66GVdNr3gjkudbhSf)w4)hqlj
  1895. G"MNjYdo9mFdXe(F5HEn6Hi2Yb9e75dFfXlimbgISgruxbH8rtZOKXdcThDh6fSeUx
  1896. IF I<>80 THEN ?:?"Page 1 is too short or long!":J=1
  1897. I=80'Page 2 of ELIZA2.LZH begins here.
  1898. G"cnuCgXmsNYUpk2hZbhbcAqSSbqxkfHzcPtrMq729LSuX2BMfJ)hej5zvSl40)O4C
  1899. G"Ldr4JPqMja3RdDS53O90xQAqlrdVCbQYWhSOjZ1dA931O2Tl6z07CTR5jmf5(SIr
  1900. G"WE2lAf3Cin0rYhlxnnI8WzNs306ZSAG5ZGm7XyYJx)6EcU7OCprrEJRRMJxA660W
  1901. G"jJx0r4(hOH0CPkOGSlhKxLkSFk1ncy7nMD9I9uj1nPVUMk2MtfL7hYnYo7syRgGN
  1902. G")t4)l7vs0g2cf40WpRoQEJhW9QYc5j)b25Ddqq9Xc(ca9G33dewq5PeqT2Qt246k
  1903. G"Qm8PYuuNsTg85l3zkiFXWo6n1BFUPDwp1lJdBDxvdU)f7XuGVxygqpXC)fJB(2FT
  1904. G"Z2)W0otxD6cXkVttLz23KePY5Tj3h1njkp6rXe9ItRJccPglQOhUlkOFUrFFKp29
  1905. G"qf(SDC5Gqcl(D3DaCPTpBlTa4u28jRU15Vgm67RQmTRNdGXtyTiKyEa5vQyGowX8
  1906. G"gs1HTQeYvLmm3RRiOYC(cPxFyDh8lKHespf0rasfvFFVn)D2JzIViD5DvKoGqFta
  1907. G"Swc6ImuqncWTBfInTIGntcHm(8BXMztsPPK8xhD)WtDjPT1U)nTwwTfKk8pBryXV
  1908. G"zYIhuFTGrpie)Q)LbaE93abLhCiWPKa3MTz3zCeTERCYJ1IyLm9yRNPs)huwqsTF
  1909. G"0yi2)eHd2rHRvUYNCYSMOV1(y3r3uOiFGXgqwSUrUFCuMqbABGT4WtXLZNVyP9Ug
  1910. G"AggyIYK8o0ZI36S5kw90ZDJJaGKoAazChyzr4AEomLdVCJanGaY44hDyGXvQn8EY
  1911. G"5xXKRLkHnv)IE9ORzAsgL2u1Sq0rEV4yOH(lT2fK8d21gMunchvOb6mOLGTZ09ry
  1912. G"mHiiZoARWlobhbglOLbmk668KUPeJbKWznc(rX2Yg(zwl634yPmMrlNhczkuHWqT
  1913. G"NhYI4hAbBuetgtqxO8D5Etge)HpPL7wojteauinsmgoODyWYAkYYQS)qwdCmfhc1
  1914. G"gx6bTC6YQdLAa3nXytetktVUCwhyc45W0AQbn0LSkvifQdwpXyikxtdn1x5C7lxZ
  1915. G"UgSqVBlj5pyoY5c5QjoRu138yIuswF1I4e2(V9a2tJ5qjePiTEio1hECkG1zHhNF
  1916. G"XsocDo)NkoD2fArtZLJ1(xj9ZLu0fBNSMLZZLYqHfHN7rmgpnOIEN)FVEMVZVfrK
  1917. G"tUEuHNmipsseIOXHbZJ8GSUlVqg(m9SWZOttzjcCFZ0UQbtH5CmtN9kRzJf4cp45
  1918. G"iDLSMrx2yNbFwixe20k9UFaCQxOfXnN4YdZJViYUoHFt4I7kaoB)abYL5wDMjihL
  1919. G"REXxQyJ1fEanOiFAqwvwiQ5mv(GM)qiq3D6VcL(3MtFqsMhylWkWswrUtpOaiPkm
  1920. G"D6Uzl7umvTzEPXcbLQpU0)thcp8KJP03fCLB5aviIjYXBY9XMJB9A7DI1V0wOheV
  1921. G"dcJsJt8PBs0Ouax8HDqNvCkoWGJFvtTd6OX2O2KQfzXTrOarGYgAzCMp0LehiRr1
  1922. G"jX75ksV6AdLPvsMz49m2IZtFFt(abvtxZ8Qva4WUwnpB(IkjYDqkHuXo)TdKmExp
  1923. G"Lw1Xh6Qd8u(zRBoxCEsZfNVneJYFSdNeObmzSLU2MmAYnBYzIeHahWS2S)Q0LAfc
  1924. G"UdM)uUqRBRXC0m9BPwr1HT7TByLS6))QurvGyloKACmRrRm0LgPAHkQzcWUUvd4a
  1925. G"sJC6IEqBpx8UJLeCGRKtj92Q3DVKGPnXSHciXB6RIiCY(wlGG88Bt6vdonhJtICs
  1926. G"U0Gn2DlUP(sVFg9wi40VvL3YyYATXm3Twfzgp9IUznJ7j1ab5mImG(RVaGIjIz2E
  1927. G"s8Py0GKtphsoTO0H9TlKl)Fk73bIklpm7NMrxitCNKeaEqB)QdMc9hIzZwhQZsSd
  1928. G"bNdrcfiduKr)ddRbXWd1aF(EqaUNr8jLk5jb2QS84lnMDydDFsd47CAJMeooQmt1
  1929. G"z1a(QIi1hKBV)8XfTZnHIutMKEvAZ70NnmRBnibOLgXeuyRc60oB5pC09UgiSCRI
  1930. G"yLJAxI5AqizmVD051ABCscCSADbDFVZJdpCfp1q6Q4ppCm2cC3w7b9RMTvq0Rgfe
  1931. G"AKeJWalPs6ha2smKZDO76(isUsBvvLpGxn1kXyhNJM(zQrEDY8)gqybd1Qt1YrbS
  1932. G"7Jxw(uA5S1b5LQn59lDpHuPpLsPQ78ieuyOaineFRSGokkJvBlOW9B2KoLo94LVK
  1933. G"YcleYFkRF0Ra7)nJhhprEn2qVgXZ9MnkEmHa6hrPh8)LoouMqhDd0f4VZLFWVikM
  1934. G"R)AM94UlzjxmGJT3MXa6YOyVS0BZsd4qMmE8NpFXji)hoMseD(I)Oi4uthlW3sGA
  1935. G"QdTQhAhtLJjWmtNTl8uI0)rYG2oerFozZvLIy8BVisGbuBMbhm9LczuoCcz1bbyL
  1936. G"PtV42O1MpIFOBBFL4ANM9)2()paIarlSHwnTS2caaGxFaaaAlwZsasajuetjPvqU
  1937. G"HiuqtH2rnbaaiihDA6ER2u(nyL5KNrlVopZMGedIyaq7YfUbiwnygGqKxttUWmVy
  1938. G"KOtdJjvr2(HJ)))V3YdusNS1E1Uh4pIMDwTFV339QTz74vf1WPtVvFKzZQ)x97nP
  1939. G"bOCi)qxCA0CXlwI)xV47b1hABsMIrUrI)WAux6hP1x9p1bRTnp94JJsHqZLIF05B
  1940. G"skkFBOdK9vI6mXe57pk2tLrx87tuOE1n9bJv1JplsWgVdLqAKQv15MrRk3wXQZCq
  1941. G"J(ZiGx9ENycfXfM9Dv3YuhLe1vc6sBaBUNbRgWM818LKDNSHY51rxC7RShdAwVYy
  1942. G"7ZR())69NfnCk1CL69kIhKVHrafFRba9HGljfjvkkxp7TtLF0I(XbFc4iTKIV1Uv
  1943. G"v(gPTRIcQC93W3ZzbzDno(o1zZcJyihzhQEfj(7eTRqOOKlbljKu4bXaT5uu2BMC
  1944. G"VWg2Dyf6vlAqAAZOLa66xOp9axWAmgiRRIdQVo6Hw8w4bL(Jk(NxYymObZMkLGVM
  1945. G"8F1Ckvb38hfYkOt98fz3mWeeeTbp7mfeMHYJNXwEI)hxeoKTI6Xc7IKwEsPGe(Kq
  1946. G"CLW)76)b5iEffcDSF73kZeD4U6sdYoIEOWVViPTNpwosfkGu1L00FUiBTLvHdBH3
  1947. G"a1ziWdKdrMgZZ5R0zAhTO(1wqSItiXOP3ruMjfQC3pPIYBd85c1QJlM)sE5hw1Q(
  1948. G"HHe9fIsWRNtGXuo71j1FFMx80lcOHhBVdV4CcVmX29OhVu4aMX58kJmQy89cAgGW
  1949. G"lbeTK5qct)5GdLV3rgtOWGwkgeggcSfmm16Ut6XjBnKrMrPIT5AqOWjGdRXDb19A
  1950. G"EFgdNfL0yXtv)oUtu6PELk6VuX2LuXYvo8K3geNO7pzA15i)TPoFLBOtIxNelDix
  1951. G"tmxCJBvOv4dh(U5BG6osxvDMZu2Gk(E78kh2tHmxKmerb1P)nVDUY70m11vTZ6gU
  1952. G"y(1sBoanhN5dH37Xxdr5nuu)WUxShca1H2dvdqJk9qZ3tLk1Z6EdG5MdHPS7n7Fw
  1953. G"WfztxGUg0aftjNmcpdaePjMdFbaGB)JG6ndDgU3YULAI)YTJcuiUmqx1JrJ1yrmR
  1954. G"NL(NcefmW)QiE)rZO(MremKWregZshaIC6ESmLPYFpN6pUlvYOIrH8uWgGFiXicK
  1955. G"Wv5OaoePR)LjMZE91SGCwXhA5TBENSwEILwqKopMcoIUe4)lLjpGKVeT01Yk0Mxu
  1956. G"nQj2pSSnKqyxTv2u3n7SgA7hVPgduOhRSu8hyTgFXVCfFJQdcJ5im6CQBUkTWmwL
  1957. G"YpfMpxQi4FaugQu(pOMF54a(ZNJ9frWVIu2mYm4fHycqCz7yyseMTRpaoyB9IITw
  1958. G"ISCvMOb7X78NhsT2KaDRhNZeG28kosm2IqLR2uWqKbl5T70V2en5o7COtpZohAv3
  1959. G"(oPJwVJYgD4Sj)ZkHw8WuDBC2w7vJiHPfqDHcKinH(U15QxysywneGR)geQKvdEz
  1960. G"rpdUzRpkjBDA(FZ9WU8OIQD(Kos65tjVWbcdv6aJqaEHEKGJ1O70Bjatu)IFzscN
  1961. G"RyPnws1nRLme2kkOHDkpf8yfw90xlfigZDOcUtshJMhUDz0A4QZHtFJzgfD)93zJ
  1962. G"LWtzegY3inFmuR7MUMZtvNiOuSw3AkFSvvo2QhX37QzooPdb)kakeM5ouSSklOyY
  1963. G"sZrMVvsuRBwT06FE)iB22cbcF4VRTYqQHliHhBcsOtDGWLcbXrG87XG9ytVGCENq
  1964. G"tCM2ueajlKdzqGddbkuw3rN6RMfVbsHdX5ugpjLP4YNziG6YNkWRaiRArSjqkhNf
  1965. G"V87jb0MtcWTRcCIZAQN9b5zthU4DGyjUEgimSZ4uTJUNpdYZsPPhrCm43tSo9R30
  1966. G"awuhAN2MtA(9KMABVQmKPb78U2V7irBWuIeV6RuVsocaON)gu6u2c0KJqEQqBrn2
  1967. G"tXOmgLUeAAOv26eE95ET3wYBrtjTcWaZz53eFfT4QkiE3kBIFbFJ1FV8urrxYGRF
  1968. G"O)JVQoUiWDDiuI7CsloUU7EkwVc8832MwRw8OSR4KuGbrLr5gwH1XfpjFHlVGWvo
  1969. G"E5nk4f1KFeviwEhi1EhO3AJJqqTjSWAmkB(LT42g7Y7BHZFdNpffSKqI9tnqISfo
  1970. G"V8cC38RSw4Q9OkvL3tsvEycRKhaDnYpj6D72enhWmx(OtI4QNGhHSXukgjKbWEds
  1971. G"8wIwQzBJXTsnfRKUjxqnjQ(nq21VNhvpp26RQ9)OQCxjn9OjTNi98pbBszDk0os1
  1972. G"rcoFgmcOxOm7ZRxBGIfDNWIadxgg2qgLavW4hHmcRSL8j9UlTYwDLsEYx2BEB(pZ
  1973. G"prlfqFLtSJ5g6sZpOF8Ihgdy8Jn1Jo7h7UsRG)BW98ecwXyINuMrqKVZIQEIFwA5
  1974. G"WIHDVWtfGwMVuu3PamZqJLcAjNj)SqQdJrm7nuQfLcW4W5b57JL7MctKslBsEE1V
  1975. G"DP5ALv7a(3AW5stcxYV3wOJkPiUMfrbSQDw9YAn7GTYcBBh54p(WnB4O92pHM00l
  1976. G"UKWVNu9G)HAHcVMVcX2eNE87S5lrCJ(Q181QQOdHItihkEVyozU21ZSn(MmE1DkV
  1977. G"ypY71lQQDU(q5njrB0)hTOrrcs2ZKs8qRA1ofqVdbN1r15ezy7otmmeLGFOFwTAm
  1978. G"5VcvO)6dIkDo8KGMa0)riTe4XvCw4AJ3dxScEUv4X153BXvlsOIxTYRiRnmr3IoF
  1979. G"MreZnoK3WGZGJ1R2I7wp)E1A59v1R3ILRWhHH6uF7UfEWT46AjJeTI5vP2Zn8b4N
  1980. G"GT3u1JFdj(Y9SVTgneHS46dWokSGefGuw97Ix9F)BSL6AOf(pOGBydpTEj1CxH3e
  1981. G"CUJqEAfudMcColllcjztGU1maBMejI3WROA2U)E1f7AvdBsqkNgcHNN4Pw0dRoyD
  1982. G"zA67la2UOFBN8M8ycGzsMvGIQvAsGtscxO)aspArbrurvVKcoKrxbnP0otouD0K0
  1983. G"EfiVDStJSBqJgeBgNs8tyOQko7SqPqeKabdxYxQ8bjCjSs9lDqZk4cRB1MnEraEH
  1984. G"Pn2GLZXey8eoEeAQCJ8)(nPqLz)gW4fbK51POgzx3MMkOm19CklQlXRxv3d2sB2J
  1985. G"TRsL0ao01VQL7dfYQDZ(G3ieSl1RlBpAJNNC0ZN5rY0MXHNmrEROv3T)kou0PKD9
  1986. IF I<>168 THEN ?:?"Page 2 is too short or long!":J=1
  1987. I=168'Page 3 of ELIZA2.LZH begins here.
  1988. G"(zWASyHtkwvhml3uxopxL3fHlb4cf0HiICe1Xo1BAoZf5fAzacri948J)ulRvpW2
  1989. G"ilwGtPZdhwwnroCzp99pH(H3tfMevflHS3WrOM)VIY304eaFM2i6T4XcBI4xeZi2
  1990. G"O3Dde75WTZc42XIBuRGxzaLu3L(zH59R7tCftTRh3PsS7sPL5BUWhWKXSjH39wbL
  1991. G"FzYCC9H1mQB1lZL0G7a3f88VQ7CbSE4ZQtscyfMs4W6l(i2op5BV8(Hj67VzAI6k
  1992. G"8ErK9ZwsRF)jbC8Uzp3WANtgJU23VzkytV4rZOE1leZ7zn)sGflk4YXcckfyrkhW
  1993. G"1Uh21Q2yx8GPPvaDmXrkZC52Yz7QgEeT2s(MZEl6(TNqw7(PsgS44sDMzs0dTEZ8
  1994. G"3q9nKOrdlyTYCmmSjxTRVeYoo9wLwZtaR2Cp)d15k0vl2zLu9JEKsRVuT0rTwlXU
  1995. G"OOqjKP7R5H3QUwOcllJ0ANd8Q8h62sBUn4tbP19h1s(y)3feCtmkUcO0VoAgHaxa
  1996. G"at39yLiNFsVfvyu4LbWGgiqh3TkIBaoN4ATyeycFs(ezftjemaXXLJxzoHN8HPkU
  1997. G"XDfMNmOZSpKkUi2Vkiamg09sJs6Qm42NgFq0AEWpen(IGDlkii0LrxvWZUus7kma
  1998. G"5GV4LwhbTqG55j7NuTHVANvx)(SV8BRZ(Xp)111x9ET3476YEjITaMfLdqlKGfaI
  1999. G"t3)TLypUUs7e2dyL7TCGMeg3S(tyS)vUP2h27zYtiLcyvy6l7B(xaDqVOLpC(WCy
  2000. G"XGuZiYVV5N5Ey5JjMdmJqc7n8vSV5O515)9NFwxi)pOm0Q90P(ek(U(sVWeZ4LNP
  2001. G"q)a(HvTWgA10IebaaaQkaaa8WhhJbibyavtnKtfrvrD2eaaaG6APPWMwkp4FZF3t
  2002. G"0rgXKwG1gx7Sdj84SgYC5DZNNKlYVNYzGFuGouCbRlmFvaFkdCWeeeA5EthsPi5j
  2003. G"Y9DVRNE(Eo29U5En7t9H870cQmXnQeyeKe7Ny5CEfUc8SiF10gIq6DS3tbfgalFu
  2004. G"FLAIKivBA3MkGwzq8vgWOdG5p6q3iE)hG9WnfBQYaS)(Yq6AeG13SfFaKkxwrcu(
  2005. G"mR7N9II5bRNnbwAP(zl0dgXRDqqLbgJP9sqrUSs9xOYJdlQFRRt5kJwuit5vX8d5
  2006. G"z(q0pVSvJmFkgf5r3baAZ7aOMu((O6NY)XDBCRS0(ZCoAlhn3fV8rQZBBFiztmW0
  2007. G"nPFtIMOJGIyrxRagJ6LOqVp(q02g4hQ9FZla"
  2008. K=255:IF I<>188 THEN ?:?"Page 3 is invalid!":END ELSE IF J THEN END
  2009. OPEN"B",1,"ELIZA2.LZH":N&=8862:FOR Q&=1 TO N&:IF L=0 THEN GOSUB G:L=6
  2010. ?(100&*Q&)\N&;"%";:W=T\P(6-L):GOSUB G:W=W OR T*P(L):B$=CHR$(W AND K)
  2011. L=L-2:PUT 1,,B$:LOCATE,1:NEXT:?"File Extracted: ELIZA2.LZH":END
  2012. G:T=INSTR(T$,MID$(A(L&\63),L& MOD 63+1,1))-1:L&=L&+1:RETURN
  2013. SUB G(B$):A(I)=MID$(B$,2):FOR Z=2 TO LEN(RTRIM$(B$)):C$=MID$(B$,Z,1)
  2014. Q=Q+ASC(C$):NEXT:I=I+1:V=(Q AND 63)<>(INSTR(T$,LEFT$(B$,1))-1):?I;
  2015. LOCATE,1:IF V THEN ?"Physical Line";I;"is bad!":EXIT SUB ELSE END SUB
  2016.  
  2017. '
  2018.  
  2019. Msg #:  512                       QUIKBAS Subboard
  2020.  From:  JANIS KRACHT              Sent: 04-04-93 11:00
  2021.    To:  ALL                       Rcvd: -NO-
  2022.    Re:  PDN BBS LIST (1 OF 2)
  2023.  
  2024. 4/3/93         =-=-=-=-PDN BBS List-=-=-=-=
  2025.  
  2026. This list represents members of the Programmer's Distribution Network
  2027. who have indicated to me that they will accept file requests for PDN
  2028. files, or Downloads on the first call, or downloads after a validation
  2029. program. This list is by no means all-inclusive, but represents only
  2030. those who have let me know via netmail that they would like to be on the
  2031. list.
  2032.  
  2033. See *Note below for FTP access.
  2034.  
  2035. KEY:
  2036. Types: HST  = USRobotics Courier HST 14.4k    V32B = CCITT v.32bis compliant
  2037.        HST+ = USRobotics Courier HST 16.8k    CSP  = Compucom CSP
  2038.        V32  = CCITT v.32 compliant            ZYX  = ZyXEL 16.8k v.32bis
  2039.  
  2040. FQ:   U=Unlisted OK,   L=only in nodelist
  2041. DL:   Y=on first call, V=after validation, LDV=Long Distance Validation
  2042. N=n/a
  2043.  
  2044. PDN:  A=all areas,     N=Not all areas
  2045. Hrs:  A=anytime but ZMH, or listed times
  2046. Node: FidoNet Node Number or UL=not in nodelist
  2047.  
  2048. = *USA* ================================================================
  2049. St:     Phone:         Type:     Fq: DL:  PDN  Hrs:           Node:
  2050. ========================================================================
  2051. AL      1-205-666-0932 HST        L   LDV   A  17:00-24:00    1:3625/454
  2052. AK      1-501-450-7010 ZYX   V32B U   Y     A  A              1:399/11
  2053. AZ      1-602-944-0524       V32B U   V     A  A              1:114/161
  2054. CA      1-916-334-4470 HST+  V32B U   Y     A  A              1:203/540
  2055. CA      1-916-334-4478 HST        U   Y     A  A              1:203/541
  2056. CA      1-714 939-6401 HST   V32B U   Y     A  A              1:103/208
  2057. CA      1-310-419-0931       V32B U   Y     A  03:00-01:00    1:102/531
  2058. CO      1-719-380-8813 HST+  V32B U   Y     A  A              1:128/60
  2059. CT      1-203-879-7122       V32B U   Y     A  A              1:141/1135
  2060.                                                               8:909/5(RBBS)
  2061. DE      1-302-995-6910 2400       U   Y     N  A              1:150/170
  2062. GA      1-912-329-8984       V32B L   LDV   N  A              1:3611/15
  2063. IL      1-708-680-9420 HST   V32b Y   Y     A  A              1:115/858
  2064. LA      1-504-386-8827       V32B U   Y     A  A              1:394/7
  2065. MA      1-508-250-0187 HST+  V32B U   V     A  A              1:324/287
  2066. MA      1-508-250-4672 HST+  V32B U   V     A  A              1:324/288
  2067. MA      1-508-256-1222 HST+  V32B U   V     A  A              1:324/291
  2068. MA      1-508-250-0135 HST+  V32B U   V     A  A              1:324/292
  2069. MS      1-601-467-0801       V32  U   Y     A  A              1:3604/15
  2070. NJ      1-908-271-5168 HST   V32B U   Y     A  A              1:107/302
  2071. NJ      1-908-572-1202 HST   V32B U   Y     A  A              1:107/309
  2072. NY      1-212-927-4980 HST+  V32B U   Y     A  A              1:278/707
  2073. NY      1-315-564-5700    V32B    U   Y     A 03:00-04:00 EST 1:2608/15
  2074. NY      1-716-381-8538 HST   V32B U   V     A  A              1:2613/210
  2075. NY      1-716-898-4366 HST   V32B U   Y     A  A              1:260/1
  2076. NY      1-914-344-0350 HST   V32B U   Y     A  A              1:272/38
  2077. NY      1-914-343-7540       V32B U   Y     A  A              1:272/100
  2078. NC      1-919-286-7738 HST   V32B U   V     A  A              1:3641/1
  2079. NC      1-919-286-4542 ZYX   V32B U   V     A  A              1:3641/224
  2080. NV      1-702-253-6527 HST+  V32B U   Y     A  A              1:209/710
  2081. NV      1-702-253-6274       V32  U   Y     A  A              1:209/710
  2082. OK      1-918-438-8260 HST+  V32b U   Y     A  A              1:170/403
  2083. PA      1-412-244-9416 2400       U   N     N  M-F 23hrs      1:129/124
  2084. TX      1-210-653-2115 ZYX   V32B U   Y     N  A              1:387/641
  2085. TX      1-210-675-4787       V32  U   Y     A  05:00-02:30    1:387/666
  2086. TX      1-512-573-0245 HST   V32B U   Y     A  A              1:3802/213
  2087. TX      1-512-572-8378    CSP     N   Y     A  A              UL
  2088. TX      1-817-483-2283       V32B U   Y     A  A              1:130/403
  2089. TX      1-915-595-4914       V.32 U   Y     A  A              1:381/106
  2090. WA      1-509-582-9493 HST+  V32B U   LDV   A  A              1:347/10
  2091. WY      1-307-686-0940 HST   V32B L   Y     A  00:30-24:00    1:316/16
  2092. = *Austria* ===========================================================
  2093. Vienna   43-1-290-3658 ZYX   V32B   U   Y     A  A
  2094. 2:310/24
  2095.  
  2096. = *Belgium* ==============================================================
  2097. Antwerp  32-3-2343790  V32B  V42B   U   Y     A  A
  2098. 2:292/855
  2099.  
  2100. = *Canada* ===============================================================
  2101. Sask.   1-306-463-3117 HST+  V32B U   Y     A  A              1:140/53
  2102. Sask.   1-306-463-4581       V32B N   Y     A  A              UL
  2103. Sask.   1-306-585-0298 HST        Y   Y     A  A              1:140/40
  2104. Quebec  1-418-648-9590 HST        L   V     A  6am-3am        1:240/507
  2105. Quebec  1-418-648-0691       V32B L   V     A  6am-3am EDT    1:240/508
  2106.  
  2107. =France ================================================================
  2108. Wervicq-Sud 33-20392225 HST+ V32B L   V     A  A              2:322/2
  2109. Wervicq-Sud 33-20399342 HST+ V32B L   V     A  A              2:322/3
  2110. Wervicq-Sud 33-20392236 HST+ V32B L   V     A  A              2:322/4
  2111.  
  2112. = Germany ==============================================================
  2113. Kronberg  49-6173-2544 HST   V32B U   V     A  08:00-18:00    2:249/3
  2114.                                                19:00-24:00    MET
  2115.  
  2116. = Italy =================================================================
  2117. Malgesso  39-332-706469 HST+ V32B U   Y     A  A              2:331/106
  2118. Malgesso  39-332-706739 HST  V32B U   Y     A  A              2:331/117
  2119. Malgesso  39-332-706009 ZYX  V32B U   Y     A  A              2:331/121
  2120. Biandrnno 39-332-767277 HST  V32B U   Y     A  A              2:331/110
  2121. Biandrnno 39-332-819044 ZYX  V32B U   Y     A  A              2:331/118
  2122. Biandrnno 39-332-767329 ZYX  V32B U   Y     A  A              2:332/122
  2123.  
  2124. = *Luxembourg* =========================================================
  2125. Strassen  +352-316702   ZYX   V32B U  Y     A  A              2:270/17
  2126.  
  2127. = *Netherlands* ========================================================
  2128. Delden    31-5407-64701 HST   V32B U  Y     A 8am-12pm CET    2:283/309
  2129.                                                               2:283/309
  2130. Den Bosh   31-73-222164 HST   V32B U  Y     A 6am-3am  CET    2:512/152
  2131. Eck & Wiel 31-3449-1909 V21   V22  U  Y     N 8am-2pm         2:500/137
  2132.                         V32B  V42B
  2133. Groningen  31-50-735035 HST   V32B U  Y     Y 8am-12pm CET    2:512/159
  2134.  
  2135. = *Sweden* ============================================================
  2136. Lerum     46-302-16565 HST        U   V     A 07:00-23:00     2:203/311
  2137. =======================================================================
  2138.  
  2139.  
  2140. *Note:
  2141.   PDN Files are available via Anonymous-FTP from ftp.ieee.org (and
  2142. mirrored to halcyon.com) in the pub/fidonet/pdn directories. IP Address
  2143. 140.98.1.1
  2144.  
  2145.   File Arrival Announcement messages are available on Internet via
  2146. mailing list. To be added to the mailing-list send e-mail to:
  2147. filebone-request@zeus.ieee.org
  2148.  
  2149. If you carry the Programmer's Distribution Network and would like to
  2150. be added to this list, please send netmail to Janis Kracht 1:272/38,
  2151. <<PRISM BBS (914)344-0350 HST,V32B.  For information about the PDN,
  2152. freq or D/L PDNINFO.ARJ from my system.
  2153.  
  2154. '
  2155.  
  2156.  
  2157.  
  2158. 'Msg #:  547                       QUIKBAS Subboard
  2159. ' From:  VICTOR YIU                Sent: 04-02-93 23:06
  2160. '   To:  ALL                       Rcvd: -NO-
  2161. '   Re:  VERY IMPORTANT MESSAGE!
  2162. '
  2163. 'Hi, All!  ========= IMPORTANT ANNOUCEMENT =========>
  2164. '
  2165. '    Finally, PostIt! 6.0 will be posted.  I won't repeat the new
  2166. 'features, but they can be found in PostIt!'s header.
  2167. '
  2168. '   It is =ESSENTIAL= that you capture the next 16 messages.  From this
  2169. 'now on, PostIt!'s scripts will not be able to be decoded by QuickBASIC
  2170. 'alone.  It will require PostIt! 6.0 to extract the file.
  2171. '
  2172. '    The new format is so much more compact -- primarily due to the
  2173. 'removal of the decoder.  It was pretty wasteful to post the decoder
  2174. 'again and again, with every binary file.  That's why it has been
  2175. 'incorporated into PostIt! 6.0.
  2176. '
  2177. '    You may wonder why this release is 16 messages long.  That may sound
  2178. 'like much, but it isn't!  The line length has been shortened to =65= and
  2179. 'page length to =85=.  All that contribute to more line wrapping, thus
  2180. 'increasing the number of posts.  The 'real' file size of PostIt! 6.0 is
  2181. 'only 1K bigger than 5.1.  Why '65'?  To make sure all people will
  2182. 'recieve PostIt! without things being truncated.
  2183. '
  2184. '    I really hope the complete PostIt! package reaches everybody reading
  2185. 'this echo.  I am excited to post my latest additions, so here it is.....
  2186. '
  2187. 'Victor
  2188. '________O_/________________________| SNIP |______________________\_O_______
  2189. '        O \                        | HERE |                      / O
  2190. 'This file created by PostIt! v6.0.
  2191. '>>> Start of page 1.
  2192.  
  2193. '     ╔═══════════════════════════════════════════════════════╗
  2194. '     ║      PostIt! THE Binary <-> BASIC Script Creator      ║
  2195. '     ╚═══════════════════════════════════════════════════════╝
  2196. '                               * * *
  2197. '     ╔═══════════════════════════════════════════════════════╗
  2198. '     ║          Postit! v6.0  by Rich Geldreich 1992         ║
  2199. '     ╟───────────────────────────────────────────────────────╢
  2200. '     ║       Decoder further optimizied by Jim Giordano      ║
  2201. '     ╟───────────────────────────────────────────────────────╢
  2202. '     ║     User Interface and Graphical embellishments by    ║
  2203. '     ║          Mark H Butler & Quinn Tyler Jackson          ║
  2204. '     ╟───────────────────────────────────────────────────────╢
  2205. '     ║    Ability to post and wrap plain code ─- as text!    ║
  2206. '     ║   Based on MsgSplit by Scott Wunsch and Victor Yiu.   ║
  2207. '     ╟───────────────────────────────────────────────────────╢
  2208. '     ║   And now, with compression and a new script format   ║
  2209. '     ║   to reduce the echo bandwidth required to post your  ║
  2210. '     ║                 file, from Victor Yiu!                ║
  2211. '     ╚═══════════════════════════════════════════════════════╝
  2212. '
  2213. 'Purpose:
  2214. ' To enable the posting of compressed listings on a text only net.
  2215. ' This program takes a binary input file and converts it to a series
  2216. ' of small, postable files which other people can capture and run to
  2217. ' get the original binary file.
  2218. '
  2219. 'Instructions:
  2220. ' Just  follow  the prompts.  You give the input & output filenames,
  2221. ' the page length and the number of lines you want reserved for your
  2222. ' stuff and it does the rest. If nothing is inputted for a prompt, a
  2223. ' default value will be used for it instead.
  2224. '
  2225. '
  2226. 'Additions by Victor Yiu:
  2227. '
  2228. '     (26 March 1993)
  2229. ' NEW!  Addition of the new high efficiency script format, saving
  2230. '   800 bytes over the old format!  Still supports the old self-
  2231. '   extracting model for compatibility.  New format allows you to
  2232. '   run the cut script from the echo without editing!  Just paste
  2233. '   all the pages together and run it through PostIt!.
  2234. '   Now, all line lengths will remain constant, even with compression.
  2235. '   It results in less unnecessary carriage returns and `G"' lines!
  2236. '   After this update, I don't see too many improvements ahead -- it's so
  2237. '   jam packed with features!  ;-)
  2238. '   Some unnecessary & ancient comments are removed for space efficiency
  2239. '   The source is also modified so that most lines are less than
  2240. '
  2241. '     (16 March 1993)
  2242. ' Victor Yiu nominated & appointed the keeper of PostIt! by Zack Jones.
  2243. '
  2244. '     (9 March 1993)
  2245. ' Version 5.1 speeds the binary decoder up and cleans the PostIt!
  2246. ' source code enormously.  Decompression routine rewritten.
  2247. ' Message splitter's tab stop expansion is now user modifiable.
  2248. '
  2249. '     (28 February 1993)
  2250. ' Now, save an average of 10% on posting object files!  This version
  2251. ' includes compression of duplicate characters.  Also fixes several
  2252. ' bugs and quirks (visual & operational), and adds a disk buffer for
  2253. ' increased conversion speed.  The text wrapping problem with
  2254. ' quotes has also been totally elimintated; now, the comments
  2255. ' starting later in the line extending past the wrap will not be
  2256. ' messed up during splitting, as is was before.  Twirler was
  2257. ' optimized/fixed (MsgSplit).  Decoder was optimized more, but more
  2258. ' code had to be added on to handle compression.
  2259. '
  2260. 'Additions by Scott Wunsch:
  2261. '     (13 February 1993)
  2262. ' PostIt! is no longer just for binary files!  It can be used to post
  2263. ' BASIC code,  and will  do so in  text format.   Code will  be word-
  2264. ' wrapped appropriately, and  underscores inserted to allow QB/PDS to
  2265. ' put it back  together  again  for you.   Unlike past  code-wrapping
  2266. ' programs, PostIt! can even handle quoted strings properly.
  2267. '
  2268. 'Additions by Mark Butler:
  2269. '     (8-30-1992)
  2270. ' Postit!  output filename now defaults to the input filename if none
  2271. ' is given.   If the input filename is 8  characters  in  length  the
  2272. ' default output filename will be truncated to the first 7 characters
  2273. ' of  the input filename.   The default output extension is now "BAS"
  2274. ' instead of nothing.  I also added a little bit of text mode "screen
  2275. ' magic" to further augment  Quinn T. Jackson's copyright screen  and
  2276. ' warning screen additions.   Fixed bug from version 2.8  that caused
  2277. ' succeeding output files after the first  one to overwrite  the same
  2278. ' filename due to the filename number suffix not incrementing. I also
  2279. ' caused the program to skip the opening screens if an input filename
  2280. ' is entered from the command line when the program is run. (I didn't
  2281. ' think folks wanted to see those screens *every* time they wanted to
  2282. ' use PostIt! Sometimes ya just want to get on with it right?)
  2283. '      (9-1-1992)
  2284. ' Hardcoded a  CHR$(32)  (a space character)  to the end of each full
  2285. ' length G-sub data line in the attempt to thwart  line truncation in
  2286. ' transit on the Net. Just a theory that I hope is correct! -> MHB
  2287. '
  2288. 'Additions and Modifications by Quinn Tyler Jackson (August 22, 1992):
  2289. '
  2290. ' Postit! now prints a warning screen, warning users of possible
  2291. ' abuse of binary-to-text posts.  Also, instead of the old '80% DONE'
  2292. ' meter, this version uses a graphical bar that looks like this:
  2293. '
  2294. ' ▓▓▓▒▒▒▒▒▒▒▒▒▒ (One block=2% completion.)
  2295. '
  2296. ' I have also added a nice starting screen, giving Rich  credit where
  2297. ' it is due!   Bells and whistles, boys!
  2298. ' <qtj>
  2299. '
  2300. 'Note to QBasic users:
  2301. ' The  COMMAND$  function  is  utilized in this version so if you are
  2302. ' using QBasic you should delete  the  lines marked "**** Delete this
  2303. ' line for QBasic use ******".   All such lines *MUST* be deleted  or
  2304. ' REMmed out for this version to work with QBasic.
  2305. '
  2306. 'Note:   The  decoder outputted  with  the  encoded  data   has  been
  2307. ' "compressed" in order to squeeze it into 8 lines.  Each line of the
  2308. ' decoder is less that 72 characters, so don't worry if it looks like
  2309. ' some lines are too long when you load it into QB.   When QB expands
  2310. ' the decoder to make  it  look  "nicer,"  some  lines will look like
  2311. ' they're too long to put on an echo, even though they aren't.   What
  2312. ' I'm trying to say is:   Only  post  the  files  outputted  by  this
  2313. ' program, don't load them into QB and resave them.
  2314. '
  2315. 'Tech stuff:
  2316. ' The output files created  by  this  program  should be "echo safe".
  2317. ' The following 64 characters are used to encode the binary file:
  2318. '
  2319. ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789()
  2320. '
  2321. ' The script file is checked at runtime to see if all of the  encoded
  2322. ' data  is  present.   Also,  a simple checksum is used to inform the
  2323. ' user if the script file was  screwed or not.   (The file created is
  2324. ' not deleted if this occurs, however.   If only a few characters are
  2325. ' garbled,   then  some  of the output file may be still extractable.
  2326. ' But if the 6-bit output  stream  falls  out of sync, then there's a
  2327. ' very good  chance  that  the  rest  of  the  archive  is  completly
  2328. ' unusable.)
  2329. '
  2330. ' If anybody has any suggestions,  or finds any bugs in this program,
  2331. ' then please drop me a message and tell me about it! -Rich Geldreich
  2332.  
  2333. '********************************************************************
  2334. DEFINT A-Z
  2335.  
  2336. CONST True = -1, False = NOT True
  2337. CONST frontpage = 0, backpage = 1   '<-- for popping the warning
  2338.                                     '    screen in and out -> MHB
  2339. DECLARE SUB CopyrightScreen ()
  2340. DECLARE SUB Delay (Secs!)
  2341. DECLARE SUB DrawBox (Uprow, Ltcol, Lorow, Rtcol, Solid)
  2342. DECLARE SUB ExtractFile ()
  2343. DECLARE SUB Initialize ()
  2344. DECLARE SUB GetInformation ()
  2345. DECLARE SUB JustDoIt ()
  2346. DECLARE SUB Linein (LineColor%)
  2347. DECLARE SUB Lineout (LineColor%)
  2348. DECLARE SUB MsgSplit (SourceFile$, RealSource$, DestFile$,_
  2349.  DestExten$, PageLength, LinesOut, LineLength) 'SAW
  2350. DECLARE SUB PrepareFile ()
  2351. DECLARE SUB PrintDecoder ()
  2352. DECLARE SUB PrintLine (A$)
  2353. DECLARE SUB PutByte (A)
  2354. DECLARE SUB PutBytes (A)
  2355. DECLARE SUB Shadow (Uprow, Ltcol, Lorow, Rtcol)
  2356. DECLARE SUB ShortCopyright ()
  2357. DECLARE SUB Twirl ()
  2358. DECLARE SUB WarningScreen ()
  2359. DECLARE FUNCTION Analyze (Filename$)
  2360. DECLARE FUNCTION CheckForFile& ()
  2361. DECLARE FUNCTION Compress$ (A$)
  2362. DECLARE FUNCTION GetInput$ (Prompt$, MaxLen%)
  2363. DECLARE FUNCTION Num2Str$ (A)
  2364. DECLARE FUNCTION ParseFileName$ ()
  2365.  
  2366. DIM SHARED Lines$(1 TO 24), Shift(5), Proplr$   ' global vars.
  2367. DIM SHARED LinesOut, PageLength, CurrentPage, FileLength
  2368. DIM SHARED LineLength, BytesOut, TotalLinesOut, NewFileFlag
  2369. DIM SHARED SourceFile$, DestFile$, DestExten$, RealSource$, ToDo$
  2370. DIM SHARED Row, Col, CheckSum, CurrentByte, CurrentBit, Char
  2371. DIM SHARED Work$, ComprChar$, Qt$, Prefix$, TabStops
  2372. DIM SHARED WhatFmt$, SmallScript
  2373.  
  2374.     Initialize
  2375.     Good$ = "abcdefghijklmnopqrstuvwxyz"
  2376.     Good$ = Good$ + UCASE$(Good$) + "0123456789#$"
  2377.  
  2378.     LineLength = 65     ' please don't change this for the
  2379.                         ' sake of safety
  2380.  
  2381.     GetInformation
  2382.  
  2383.     IF ToDo$ = "E" THEN ExtractFile
  2384.  
  2385.     IF WhatFmt$ = "N" THEN   'Launch code wrapper if wanted
  2386.         MsgSplit SourceFile$, RealSource$, DestFile$,_
  2387.  DestExten$, PageLength, LinesOut, LineLength
  2388.     END IF
  2389.  
  2390.     T! = TIMER      ' start timer
  2391.  
  2392.     PrepareFile     ' open file, print header, etc.
  2393.     JustDoIt        ' do the binary stuff
  2394.     PrintDecoder    ' print decoder, close file
  2395.  
  2396.     T! = TIMER - T!  ' stop timer
  2397.  
  2398.     LOCATE Row, Col
  2399.     PRINT "          "
  2400.     PRINT
  2401.     PRINT TotalLinesOut; "lines in"; CurrentPage;
  2402.     PRINT "file(s) written."
  2403.     PRINT USING "Elapsed time: ##.# secs."; T!
  2404. END
  2405.  
  2406. FUNCTION Analyze (Filename$)
  2407.  
  2408. OPEN Filename$ FOR BINARY AS #5
  2409.  
  2410. Tmp$ = INPUT$(20, #5)
  2411. FOR A = 1 TO 20
  2412.   Ch$ = MID$(Tmp$, A, 1)
  2413.   IF Ch$ < " " THEN Analyze = True: EXIT FOR
  2414.   IF Ch$ > "~" THEN HiASCII = HiASCII + 1
  2415. NEXT
  2416. IF HiASCII > 12 THEN Analyze = True
  2417.  
  2418. CLOSE #5
  2419.  
  2420. END FUNCTION
  2421.  
  2422. FUNCTION CheckForFile&
  2423.  
  2424. OPEN SourceFile$ FOR BINARY AS #1
  2425. A& = LOF(1)
  2426. IF A& = 0 THEN
  2427.     CLOSE
  2428.     KILL SourceFile$
  2429.     PRINT "   File not found."
  2430. END IF
  2431. CheckForFile& = A&
  2432.  
  2433. END FUNCTION
  2434.  
  2435. SUB CopyrightScreen
  2436. Linein 1
  2437. COLOR 15, 1
  2438. LOCATE 4, 1
  2439. PRINT "        ▒▒▒▒▒▒▒▒▒▄                                       "+_
  2440. "     ▒▒▄"
  2441. PRINT "         ▒▒█▀▀▀▒▒█                                       "+_
  2442. "     ▒▒█"
  2443. PRINT "         ▒▒█   ▒▒█ ▒▒▒▒▒▒▄ ▒▒▒▒▒▒▄ ▒▒▒▒▒▒▒▒▄ ▒▒▒▒▄"+_
  2444. " ▒▒▒▒▒▒▒▒▄  ▒▒█"
  2445. PRINT "         ▒▒▒▒▒▒▒▒█ ▒▒█▀▒▒█ ▒▒█▀▀▀▀  ▀▀▒▒█▀▀▀  ▒▒█▀ "+_
  2446. " ▀▀▒▒█▀▀▀  ▒▒█"
  2447. PRINT "         ▒▒█▀▀▀▀▀▀ ▒▒█ ▒▒█ ▒▒▒▒▒▒▄    ▒▒█     ▒▒█     ▒▒█"+_
  2448. "     ▒▒█"
  2449. PRINT "         ▒▒█       ▒▒█ ▒▒█  ▀▀▀▒▒█    ▒▒█     ▒▒█     ▒▒█"+_
  2450. "      ▀▀"
  2451. PRINT "        ▒▒▒▒█      ▒▒▒▒▒▒█ ▒▒▒▒▒▒█    ▒▒█    ▒▒▒▒█    ▒▒█"+_
  2452. "     ▒▒▄"
  2453. PRINT "         ▀▀▀▀       ▀▀▀▀▀▀  ▀▀▀▀▀▀     ▀▀     ▀▀▀▀     ▀▀"+_
  2454. "      ▀▀  v6.0"
  2455. COLOR 14, 1
  2456. PRINT "                ╥ ╥ ┬ ╥──┐ ─╥─ ╓─╥─┐ ╓─╥─┐ ╥──┐ ╓─╖ ┬   "+_
  2457. " ╥─┐  ╥  ┬"
  2458. PRINT "                ║ ║ │ ╟─┬┘  ║    ║     ║   ╟─   ║ ║ │   "+_
  2459. " ╟─┴┐ ╙──┤"
  2460. PRINT "                ╙─╨─┘ ╨ ┴─ ─╨─   ╨     ╨   ╨──┘ ╨ ╙─┘   "+_
  2461. " ╨──┘ ╙──┘"
  2462. PRINT "        ╥──┐ ─╥─ ╓──┐ ╥  ┬    ╓─── ╥──┐ ╥─   ╓─┐  ╥──┐"+_
  2463. " ╥──┐ ─╥─ ╓──┐ ╥  ┬"
  2464. PRINT "        ╟─┬┘  ║  ║    ╟──┤    ║ ┌┐ ╟─   ║    ║ └┐ ╟─┬┘ ╟─"+_
  2465. "    ║  ║    ╟──┤"
  2466. PRINT "        ╨ ┴─ ─╨─ ╙──┘ ╨  ┴    ╙──┘ ╨──┘ ╨──┘ ╙──┘ ╨ ┴─"+_
  2467. " ╨──┘ ─╨─ ╙──┘ ╨  ┴"
  2468. PRINT
  2469. COLOR 13, 1
  2470. PRINT SPC(22); "Decoder revisions by Jim Giordano."
  2471. PRINT SPC(19); "Graphical & user interface revisions by"
  2472. PRINT SPC(20); "Mark H Butler and Quinn Tyler Jackson."
  2473. PRINT SPC(21); "Text code wrapping by Scott Wunsch."
  2474. PRINT SPC(16); "Compression & new script format by Victor Yiu."
  2475. COLOR 15
  2476. Solid = False
  2477. DrawBox 1, 1, 25, 80, Solid
  2478.  
  2479. COLOR 7
  2480. Delay 5
  2481. WarningScreen
  2482.  
  2483. Delay 1
  2484. Lineout 1
  2485.  
  2486. COLOR 15, 0
  2487. CLS
  2488. PRINT "PostIt! Version 6.0"
  2489. PRINT
  2490.  
  2491. END SUB
  2492.  
  2493. SUB Delay (Secs!)
  2494.  
  2495. Begin! = TIMER
  2496. DO
  2497. LOOP UNTIL ((TIMER - Begin!) >= Secs!) OR (Begin! > TIMER)
  2498.  
  2499. END SUB
  2500.  
  2501. SUB DrawBox (Uprow, Ltcol, Lorow, Rtcol, Solid)
  2502.  
  2503. wide = Rtcol - Ltcol - 1
  2504. LOCATE Uprow, Ltcol
  2505. PRINT CHR$(201); STRING$(wide, CHR$(205)); CHR$(187);
  2506. FOR I = Uprow + 1 TO Lorow - 1
  2507.     LOCATE I, Ltcol
  2508.     PRINT CHR$(186);
  2509.     IF Solid THEN PRINT SPACE$(wide);
  2510.     LOCATE I, Rtcol
  2511.     PRINT CHR$(186);
  2512. NEXT
  2513. LOCATE Lorow, Ltcol
  2514. PRINT CHR$(200); STRING$(wide, CHR$(205)); CHR$(188);
  2515.  
  2516. END SUB
  2517. SUB ExtractFile
  2518. SHARED Good$
  2519.  
  2520. PRINT
  2521. PRINT "Examining "; SourceFile$; "..."
  2522. COLOR 7
  2523. CLOSE
  2524. OPEN SourceFile$ FOR INPUT AS #1 LEN = 4096     ' open file
  2525.  
  2526. DO
  2527.     IF NOT EOF(1) THEN
  2528.         LINE INPUT #1, A$
  2529.     ELSE
  2530.         GOTO ErrorReading
  2531.     END IF
  2532. LOOP WHILE LEFT$(A$, 13) <> "~PostIt! 6.0~"  'search for header
  2533.  
  2534. NewFile$ = MID$(A$, 14)
  2535. NxtTilde = INSTR(NewFile$, "~")
  2536.  
  2537. IF NxtTilde = 0 THEN GOTO ErrorReading
  2538. NewFile$ = LEFT$(NewFile$, NxtTilde - 1)  ' get filename
  2539. OPEN NewFile$ FOR BINARY AS #2                     ' open...
  2540.  
  2541. PRINT "Loading "; SourceFile$; "..."
  2542.  
  2543. DO
  2544.     IF EOF(1) THEN GOTO ErrorReading    ' end of file already?
  2545.  
  2546.     LINE INPUT #1, A$                      ' get a line
  2547.  
  2548.     SELECT CASE LEFT$(A$, 1)
  2549.         CASE "~"
  2550.             IF NOT QuoteOn THEN
  2551.                 EXIT DO                     ' end; quit loop
  2552.             END IF
  2553.         CASE "a" TO "z", "A" TO "Z", "#", "$", "(" TO "9"
  2554.             IF NOT QuoteOn THEN
  2555.                 FOR Q = 2 TO 9              ' expand the string
  2556.                     Look$ = MID$(ComprChar$, Q - 1, 1)
  2557.                     S = 1
  2558.                     DO
  2559.                         S = INSTR(S, A$, Look$)
  2560.                         IF S THEN
  2561.                             A$ = LEFT$(A$, S - 1) + STRING$(Q,_
  2562.  97) + MID$(A$, S + 1)
  2563.                         END IF
  2564.                     LOOP WHILE S
  2565.                 NEXT
  2566.  
  2567.                 Dat$ = Dat$ + RTRIM$(A$)   ' nope, collect dust
  2568.             END IF
  2569.         CASE "'"
  2570.             QuoteOn = NOT QuoteOn
  2571.         CASE ELSE                     ' just comments or junk
  2572.     END SELECT
  2573. LOOP
  2574.  
  2575. Siz = VAL(MID$(A$, 2))                ' extract size of file
  2576.  
  2577. NxtNum = INSTR(2, A$, "~")            ' look 4 next ~ occurence
  2578. IF NxtNum = 0 THEN GOTO ErrorReading  ' none?  Error!
  2579. CheckVal = VAL(MID$(A$, NxtNum + 1))  ' get checkval
  2580.  
  2581. PRINT "Decoding "; SourceFile$; "..."
  2582. PRINT STRING$(50, 178);     ' print initial bar
  2583. LOCATE , , 0
  2584.  
  2585. DIM P(6)
  2586. FOR P = 0 TO 6: P(P) = 2 ^ P: NEXT
  2587.  
  2588. n = Siz
  2589. k = 255
  2590.  
  2591. V! = 50 / n
  2592. FOR A = 1 TO n          ' decode file
  2593.     IF L = 0 THEN
  2594.         GOSUB G
  2595.         L = 6
  2596.  
  2597.         LOCATE , 1
  2598.         PRINT STRING$(V! * A, 177);
  2599.     END IF
  2600.  
  2601.     W = T \ P(6 - L)
  2602.     GOSUB G
  2603.     W = W OR T * P(L)
  2604.     L = L - 2
  2605.     B$ = CHR$(W AND k)
  2606.     PUT 2, , B$
  2607. NEXT
  2608.  
  2609. PRINT
  2610. PRINT
  2611. IF (C = CheckVal) AND (LOF(2) = Siz) THEN
  2612.     PRINT NewFile$; " successfully extracted."
  2613. ELSE
  2614.     PRINT "Bad checksum or incomplete script!"
  2615. END IF
  2616.  
  2617. CLOSE
  2618. END
  2619.  
  2620. G:
  2621.     I = I + 1: T = INSTR(Good$, MID$(Dat$, I, 1)) - 1
  2622.     C = (C + T) * 2: C = C \ 256 + (C AND 255)
  2623. RETURN
  2624.  
  2625. ErrorReading:
  2626.     CLOSE
  2627.     PRINT "Error reading script."
  2628.     END
  2629. END SUB
  2630.  
  2631. SUB GetInformation
  2632.  
  2633. SourceFile$ = LTRIM$(RTRIM$(COMMAND$))
  2634.     '**** Remark the above line for QBasic ***
  2635.  
  2636. IF LEN(SourceFile$) <> 0 THEN
  2637.     ShortCopyright
  2638.     A& = CheckForFile
  2639.     IF A& = 0 THEN END
  2640. ELSE
  2641.     CopyrightScreen
  2642.  
  2643.     DO
  2644.         SourceFile$ = UCASE$(GetInput$("Input filename"+_
  2645. " (text/binary)? ", -1))
  2646.         IF LEN(SourceFile$) THEN
  2647.             A& = CheckForFile
  2648.         ELSE
  2649.             END
  2650.         END IF
  2651.     LOOP UNTIL A&
  2652.     PRINT
  2653. END IF
  2654.  
  2655. A = 8192                        ' PostIt! 6.0 script?
  2656. IF LOF(1) < A THEN A = LOF(1)
  2657. A$ = INPUT$(A, 1)
  2658. IF INSTR(A$, "~PostIt! 6.0~") THEN
  2659.     A$ = ""
  2660.     ToDo$ = "E"
  2661.     EXIT SUB
  2662. ELSE
  2663.     A$ = ""
  2664.     ToDo$ = "M"
  2665. END IF
  2666.  
  2667. DefaultFile$ = ParseFileName$
  2668.  
  2669. Recommend = Analyze(SourceFile$)
  2670. COLOR 15
  2671. PRINT "I recommend using the ";
  2672. COLOR 13
  2673. IF Recommend THEN
  2674.     PRINT "binary script (Y)";
  2675.     R$ = "Y"
  2676. ELSE
  2677.     PRINT "message wrapper (N)";
  2678.     R$ = "N"
  2679. END IF
  2680. COLOR 15
  2681. PRINT " on this file."
  2682.  
  2683. WhatFmt$ = UCASE$(GetInput$("Which format [" + R$ + "]? ", 1))
  2684. IF (WhatFmt$ <> "Y") AND (WhatFmt$ <> "N") THEN WhatFmt$ = R$
  2685. LOCATE CSRLIN - 1, 19
  2686. PRINT WhatFmt$
  2687.  
  2688. 'max file size is actually about 24576 bytes
  2689. '(because 24576*1.33333 is >32767)
  2690.  
  2691. IF WhatFmt$ = "Y" THEN
  2692.     IF A& > 24550 THEN
  2693.         COLOR 7: PRINT
  2694.         PRINT "Binary file exceeds maximum size of 24K!"
  2695.         END
  2696.     ELSE
  2697.         FileLength = A&
  2698.     END IF
  2699.  
  2700.   A$ = UCASE$(GetInput$("Use condensed script format [Y]? ", 1))
  2701.     IF A$ <> "N" THEN
  2702.         SmallScript = True
  2703.         A$ = "Y"
  2704.     END IF
  2705.     LOCATE CSRLIN - 1, 34
  2706.     PRINT A$
  2707. ELSE
  2708.     PRINT
  2709.     A$ = "Expand tabs to how many spaces [4]? "
  2710.     TabStops = VAL(GetInput$(A$, 1))
  2711.     IF TabStops <= 0 THEN
  2712.         TabStops = 4
  2713.         LOCATE CSRLIN - 1, 36
  2714.         PRINT TabStops
  2715.     END IF
  2716. END IF
  2717. PRINT
  2718.  
  2719. A$ = "What is the destination prefix (max. 6 chars.) ["
  2720. DestFile$ = UCASE$(GetInput$(A$ + DefaultFile$ + "]? ", 6))
  2721. IF LEN(DestFile$) = 0 THEN
  2722.     DestFile$ = DefaultFile$
  2723.     LOCATE CSRLIN - 1, 52 + LEN(DefaultFile$)
  2724.     PRINT DefaultFile$
  2725. END IF
  2726.  
  2727. IF SmallScript THEN
  2728.     DExt$ = ".PI6"
  2729. ELSE
  2730.     DExt$ = ".BAS"
  2731. END IF
  2732. DestExten$ = UCASE$(GetInput$("What is the destination extension"+_
  2733. " (max. 3 chars.) [" + DExt$ + "]? ", 3))
  2734. IF LEN(DestExten$) = 0 THEN
  2735.     DestExten$ = DExt$
  2736.     LOCATE CSRLIN - 1, 59
  2737.     PRINT DExt$
  2738. ELSEIF INSTR(DestExten$, ".") = 0 THEN
  2739.     DestExten$ = "." + DestExten$
  2740. END IF
  2741.  
  2742. PageLength = VAL(GetInput$("Page length [85]? ", 3))
  2743. IF PageLength < 5 THEN
  2744.     PageLength = 85
  2745.     LOCATE CSRLIN - 1, 19
  2746.     PRINT "85 "
  2747. END IF
  2748.  
  2749. LinesOut$ = GetInput$("Lines to reserve on first message [5]? ",_
  2750.  2)
  2751. LinesOut = VAL(LinesOut$)
  2752. IF (LEN(LinesOut$) = 0) OR (LinesOut < 0) THEN
  2753.     LinesOut = 5
  2754.     LOCATE CSRLIN - 1, 40
  2755.     PRINT "5 "
  2756. END IF
  2757.  
  2758. LOCATE , , 0
  2759. END SUB
  2760.  
  2761. ' Yep, the same one I released, except stripped of comments and
  2762. ' some features.  -VY
  2763. FUNCTION GetInput$ (Prompt$, MaxLen)
  2764.  
  2765. Null$ = CHR$(0): SpaceBar$ = " "
  2766. Insrt$ = Null$ + "R": Delete$ = Null$ + "S"
  2767. LeftK$ = Null$ + "K": RightK$ = Null$ + "M"
  2768. Home$ = Null$ + "G": End$ = Null$ + "O"
  2769.  
  2770. IF MaxLen < 1 THEN MaxLen = 80 - LEN(Prompt$) - POS(0)
  2771.  
  2772. COLOR 14
  2773. PRINT Prompt$;
  2774. StartX = POS(0): Cursor = 1
  2775. Insrt = True
  2776. COLOR 7
  2777.  
  2778. DO
  2779.     IF Updt THEN
  2780.         LOCATE , StartX, 0
  2781.         PRINT OutS$; SpaceBar$;
  2782.         Updt = False
  2783.     END IF
  2784.  
  2785.     LOCATE , Cursor + StartX - 1, 1, (NOT Insrt) * -7, 16
  2786.     DO: I$ = INKEY$
  2787.     LOOP UNTIL LEN(I$)
  2788.  
  2789.     IF LEN(I$) = 1 THEN
  2790.         Updt = True
  2791.  
  2792.         SELECT CASE ASC(I$)
  2793.         CASE IS >= 32
  2794.             IF (NOT Insrt) OR (LEN(OutS$) < MaxLen) THEN
  2795.                 IF Cursor > 0 THEN
  2796.                     OutS$ = LEFT$(OutS$, Cursor - 1) + I$ +_
  2797.  MID$(OutS$, Cursor - (NOT Insrt))
  2798.                 ELSE
  2799.                     OutS$ = I$
  2800.                 END IF
  2801.                 Cursor = Cursor + 1
  2802.             ELSE
  2803.                 Updt = False
  2804.             END IF
  2805.         CASE 8
  2806.             IF LEN(OutS$) AND (Cursor > 1) THEN
  2807.                 OutS$ = LEFT$(OutS$, Cursor - 2) + MID$(OutS$,_
  2808.  Cursor)
  2809.                 Cursor = Cursor - 1
  2810.             ELSE
  2811.                 Updt = False
  2812.             END IF
  2813.         CASE 13
  2814.             EXIT DO
  2815.         CASE 27
  2816.             IF LEN(OutS$) > 0 THEN
  2817.                 LOCATE , StartX, 0
  2818.                 PRINT SPACE$(LEN(OutS$) + 1);
  2819.  
  2820.                 OutS$ = ""
  2821.                 Cursor = 1
  2822.                 Updt = False
  2823.             ELSE
  2824.                 EXIT DO
  2825.             END IF
  2826.         END SELECT
  2827.     ELSE    ' extended ASCII code
  2828.         SELECT CASE I$
  2829.         CASE LeftK$
  2830.             IF Cursor > 1 THEN Cursor = Cursor - 1
  2831.         CASE RightK$
  2832.             IF Cursor < LEN(OutS$) + 1 THEN Cursor = Cursor + 1
  2833.         CASE Delete$
  2834.             IF LEN(OutS$) > 0 AND (Cursor < LEN(OutS$)) THEN
  2835.                 OutS$ = LEFT$(OutS$, Cursor - 1) + MID$(OutS$,_
  2836.  Cursor + 1)
  2837.                 Updt = True
  2838.             END IF
  2839.         CASE Home$
  2840.             Cursor = 1
  2841.         CASE End$
  2842.             Cursor = LEN(OutS$) + 1
  2843.         CASE Insrt$
  2844.             Insrt = NOT Insrt
  2845.         END SELECT
  2846.     END IF
  2847. LOOP
  2848.  
  2849. LOCATE , , 1, 0, 16
  2850. PRINT
  2851.  
  2852. GetInput$ = LTRIM$(RTRIM$(OutS$))
  2853.  
  2854. END FUNCTION
  2855.  
  2856. SUB Initialize
  2857.  
  2858. FOR DefShift = 0 TO 5
  2859.     Shift(DefShift) = 2 ^ DefShift
  2860. NEXT
  2861.  
  2862. ComprChar$ = "()*+,-./"
  2863. Proplr$ = CHR$(179) + "/-\"
  2864. Qt$ = CHR$(34)
  2865. A$ = " "
  2866.  
  2867. CurrentPage = 1
  2868. Work$ = Prefix$
  2869. CurrentBit = 0
  2870. Char = 0
  2871.  
  2872. LOCATE , , 0
  2873.  
  2874. END SUB
  2875.  
  2876. SUB JustDoIt
  2877.  
  2878. SEEK #1, 1
  2879. LinesOut = LinesOut + 2     ' compensate for header
  2880. TotalLinesOut = 3
  2881. DO
  2882.     CurrentByte = SEEK(1)
  2883.     L& = FileLength - CurrentByte + 1 ' what's left?
  2884.     SELECT CASE L&
  2885.         CASE IS > 4096
  2886.             Block$ = SPACE$(4096)
  2887.         CASE IS <= 0
  2888.             EXIT DO
  2889.         CASE ELSE
  2890.             Block$ = SPACE$(L&)     ' rest of it
  2891.     END SELECT
  2892.     GET #1, , Block$
  2893.  
  2894.     FOR Pointr = 1 TO LEN(Block$)
  2895.         IF (Pointr AND 15) = 0 THEN
  2896.             CurrentByte = CurrentByte + 16
  2897.             Twirl
  2898.         END IF
  2899.         PutBytes ASC(MID$(Block$, Pointr, 1))
  2900.     NEXT
  2901. LOOP
  2902.  
  2903.     'flush the input buffer if it contains any bits
  2904. IF CurrentBit > 0 THEN CurrentBit = -1: PutByte Char
  2905.  
  2906. IF LEN(Work$) > 2 THEN
  2907.     IF SmallScript THEN
  2908.         PrintLine Work$
  2909.     ELSE
  2910. 'flush the line buffer if it contains any characters
  2911. 'Add a CHR$(34) to it just in case a mail reader decides
  2912. 'to add some extra spaces to the end...
  2913.         PrintLine Work$ + CHR$(34)
  2914.     END IF
  2915. END IF
  2916.  
  2917. END SUB
  2918.  
  2919. SUB Linein (LineColor) '*** By Mark H Butler
  2920. Lines$(2) = SPACE$(39) + "■" + SPACE$(2)
  2921. Lines$(1) = SPACE$(39) + "." + SPACE$(2)
  2922. Lines$(23) = STRING$(80, "─")
  2923. Sp = 39
  2924. Ln = 0
  2925. FOR I = 2 TO 21
  2926.     Lines$(I) = SPACE$(Sp) + STRING$(Ln, "─") + SPACE$(2)
  2927.     Sp = Sp - 2
  2928.     Ln = Ln + 4
  2929. NEXT
  2930.  
  2931. COLOR LineColor, 0
  2932. FOR I = 1 TO 23
  2933.     LOCATE 13, 1
  2934.     PRINT Lines$(I);
  2935.     Delay .03
  2936. NEXT
  2937.  
  2938. COLOR 15, LineColor
  2939. X = 12
  2940. y = 13
  2941. FOR I = 1 TO 13
  2942.     LOCATE y, 1
  2943.     PRINT STRING$(80, " ");
  2944.     LOCATE X, 1
  2945.     PRINT STRING$(80, " ");
  2946.     DrawBox X, 1, y, 80, -1
  2947.     Delay .03
  2948.     IF X > 1 THEN X = X - 1
  2949.     y = y + 1
  2950. NEXT
  2951.  
  2952. END SUB
  2953.  
  2954. SUB Lineout (LineColor)  '*** By Mark H Butler
  2955.  
  2956. Lines$(1) = STRING$(80, "─")
  2957. Sp = 2
  2958. Ln = 76
  2959. FOR I = 2 TO 21
  2960.     Lines$(I) = SPACE$(Sp) + STRING$(Ln, "─") + SPACE$(2)
  2961.     Sp = Sp + 2
  2962.     Ln = Ln - 4
  2963. NEXT
  2964. Lines$(22) = SPACE$(39) + "■" + SPACE$(2)
  2965. Lines$(23) = SPACE$(39) + "." + SPACE$(2)
  2966.  
  2967. COLOR 0, 0
  2968. X = 1
  2969. y = 25
  2970. FOR I = 1 TO 12
  2971.     LOCATE y, 1
  2972.     PRINT STRING$(80, CHR$(32));
  2973.     LOCATE X, 1
  2974.     PRINT STRING$(80, CHR$(32));
  2975.     Delay .03
  2976.     X = X + 1
  2977.     y = y - 1
  2978. NEXT
  2979. COLOR LineColor, 0
  2980. FOR I = 1 TO 23
  2981.     LOCATE 13, 1: PRINT Lines$(I);
  2982.     Delay .03
  2983. NEXT
  2984. COLOR 7
  2985. CLS
  2986.  
  2987. END SUB
  2988.  
  2989. SUB MsgSplit (Filename$, TheName$, OutN$, Ext$, LPP, Reserve,_
  2990.  LineLength)
  2991.  
  2992. CLOSE
  2993. OPEN Filename$ FOR INPUT AS #1
  2994.  
  2995. Tab$ = CHR$(9): TabSub$ = SPACE$(TabStops)
  2996. LinesOut = Reserve + 1
  2997. FileOutNum = 1: OnMsgNumber = 1
  2998. LPP = LPP - 4   ' lines per page
  2999.  
  3000. Base$ = LEFT$(OutN$, 6)
  3001.  
  3002. Ext$ = RIGHT$(Ext$, 3)
  3003.  
  3004. COLOR 7, 0
  3005. PRINT
  3006.  
  3007. DO
  3008.     OutN$ = Base$ + Num2Str$(FileOutNum)
  3009.  
  3010.     IF Row THEN LOCATE Row, Col: PRINT "         "
  3011.     PRINT "Now writing: " + OutN$ + "." + Ext$ + " ";
  3012.     Row = CSRLIN: Col = POS(0)
  3013.  
  3014.     OPEN OutN$ + "." + Ext$ FOR OUTPUT AS #2
  3015.  
  3016.     IF OnMsgNumber > 1 THEN
  3017.         PRINT #2, "'>>> Start of page"; STR$(OnMsgNumber); "."
  3018.         PRINT #2,
  3019.     ELSE
  3020.         GOSUB Snip
  3021.         PRINT #2, "'This file created by PostIt! v6.0."
  3022.         PRINT #2, "'>>> Start of page"; STR$(OnMsgNumber); "."
  3023.         PRINT #2,
  3024.     END IF
  3025.  
  3026.     TooLong = False
  3027.     FOR Trans = LinesOut TO LPP
  3028.         Percent = (100& * SEEK(1)) \ LOF(1)
  3029.         Twirler$ = MID$("|/─\", (Percent AND 3) + 1, 1)
  3030.         LOCATE Row, Col: PRINT USING "! ###%"; Twirler$; Percent;
  3031.  
  3032.         IF NOT EOF(1) THEN
  3033.             IF Trans = LinesOut THEN
  3034.                 DO: LINE INPUT #1, Buf$
  3035.                 LOOP WHILE LEN(Buf$) = 0
  3036.             ELSE
  3037.                 LINE INPUT #1, Buf$
  3038.                 Buf$ = RTRIM$(Buf$)
  3039.             END IF
  3040.  
  3041.             Tb = INSTR(Buf$, Tab$)  'remove those dang chr$(8)s
  3042. ' (tabs)
  3043.             IF Tb THEN
  3044.                 DO
  3045.                     Buf$ = LEFT$(Buf$, Tb - 1) + TabSub$ +_
  3046.  MID$(Buf$, Tb + 1)
  3047.                     Tb = INSTR(Tb, Buf$, Tab$)
  3048.                 LOOP WHILE Tb
  3049.             END IF
  3050.  
  3051. Wrapping:
  3052.             IF (LEN(Buf$) > LineLength) AND (LEFT$(Buf$, 1) <>_
  3053.  "'") THEN
  3054.                 Trans = Trans + 1
  3055.                 CommentOn = False
  3056.                 FOR A = LineLength TO 40 STEP -1
  3057.                     IF MID$(Buf$, A, 1) = " " THEN
  3058.                         WrapPoint = A
  3059.                         EXIT FOR
  3060.                     END IF
  3061.                 NEXT
  3062.                 IF WrapPoint = 0 THEN WrapPoint = LineLength
  3063.  
  3064.                 QuotesOn = False
  3065.                 FOR A = 1 TO WrapPoint
  3066.                     Temp$ = MID$(Buf$, A, 1)
  3067.                     IF Temp$ = Qt$ THEN
  3068.                         QuotesOn = NOT QuotesOn
  3069.                     ELSEIF NOT QuotesOn THEN
  3070.                         IF (Temp$ = "'") OR (UCASE$(MID$(Buf$,_
  3071.  A, 4)) = "REM ") THEN
  3072.                             CommentOn = True
  3073.                             EXIT FOR
  3074.                         END IF
  3075.                     END IF
  3076.                 NEXT
  3077.  
  3078.                 Long$ = Buf$
  3079.                 IF CommentOn THEN
  3080.                     Buf$ = LEFT$(Buf$, WrapPoint - 1)
  3081.                 ELSE
  3082.                     IF QuotesOn THEN
  3083.                         Buf$ = LEFT$(Buf$, WrapPoint - 1) + Qt$_
  3084.  + "+_"
  3085.                     ELSE
  3086.                         Buf$ = LEFT$(Buf$, WrapPoint - 1) + "_"
  3087.                     END IF
  3088.                 END IF
  3089.  
  3090.                 IF NOT ((Trans = LPP) AND LEN(Buf$) = 0) THEN
  3091.                     PRINT #2, Buf$
  3092.                 END IF
  3093.  
  3094.                 Buf$ = MID$(Long$, WrapPoint)
  3095.                 IF CommentOn THEN Buf$ = "'" + Buf$
  3096.                 IF QuotesOn THEN Buf$ = Qt$ + Buf$
  3097.  
  3098.                 GOTO Wrapping
  3099.             END IF
  3100.  
  3101.             IF NOT ((Trans = LPP) AND LEN(Buf$) = 0) THEN
  3102.                 PRINT #2, Buf$
  3103.             END IF
  3104.         END IF
  3105.     NEXT
  3106.     IF NOT EOF(1) THEN
  3107.         PRINT #2,
  3108.         PRINT #2, "'>>> Continued on page"; OnMsgNumber + 1
  3109.     ELSE
  3110.         PRINT #2,
  3111.         GOSUB Snip
  3112.         PRINT #2,
  3113.     END IF
  3114.  
  3115.     CLOSE #2
  3116.     IF NOT EOF(1) THEN
  3117.         OnMsgNumber = OnMsgNumber + 1
  3118.         FileOutNum = FileOutNum + 1
  3119.         LinesOut = 1
  3120.     END IF
  3121. LOOP UNTIL EOF(1)
  3122. CLOSE
  3123.  
  3124. LOCATE Row, Col
  3125. PRINT "         "
  3126. PRINT
  3127. PRINT "Complete!"
  3128. END
  3129.  
  3130. Snip:
  3131.     PRINT #2, "'________O_/________________________| SNIP"+_
  3132. " |______________________\_O_______"
  3133.     PRINT #2, "'        O \                        | HERE |     "+_
  3134. "                 / O"
  3135. RETURN
  3136.  
  3137. END SUB
  3138.  
  3139. 'Converts a number to a string lacking a leading space.
  3140. FUNCTION Num2Str$ (A)
  3141.  
  3142. Num2Str$ = MID$(STR$(A), 2)
  3143.  
  3144. END FUNCTION
  3145.  
  3146. FUNCTION ParseFileName$
  3147.  
  3148.     'Get the source filename without the drive & path
  3149. FOR S = LEN(SourceFile$) TO 1 STEP -1
  3150.     IF INSTR("\:", MID$(SourceFile$, S, 1)) THEN EXIT FOR
  3151. NEXT
  3152. RealSource$ = MID$(SourceFile$, S + 1)
  3153.  
  3154.     'Get destination prefix & extenstion.
  3155. Ext = INSTR(RealSource$, ".")
  3156. IF Ext <> 0 THEN
  3157.     DestTemp$ = LEFT$(RealSource$, Ext - 1)
  3158. ELSE
  3159.     DestTemp$ = RealSource$
  3160. END IF
  3161.  
  3162. ParseFileName = UCASE$(LEFT$(DestTemp$, 7))
  3163.  
  3164. END FUNCTION
  3165.  
  3166. SUB PrepareFile
  3167.  
  3168. F$ = UCASE$(DestFile$ + Num2Str$(CurrentPage) + DestExten$)
  3169.  
  3170. COLOR 7: PRINT
  3171. PRINT "Now writing: "; F$; " ";
  3172. Row = CSRLIN: Col = POS(0)
  3173.  
  3174.     'use 8k output buffer for a little speed
  3175. OPEN F$ FOR OUTPUT AS #2 LEN = 8192
  3176.  
  3177. IF SmallScript THEN
  3178.     PRINT #2, "~PostIt! 6.0~"; RealSource$; "~"; "Script starts"
  3179.     Prefix$ = ""
  3180. ELSE
  3181.  
  3182. 'Print the first 3 lines of the decoder.
  3183. ' Shaved several bytes... -VY
  3184.  
  3185. PRINT #2, "CLS:?STRING$(50,178):DEFINT A-Z 'Created by PostIt!"+_
  3186. " 6.0"
  3187. PRINT #2, "FOR A=0 TO 6:P(A)=2^A:NEXT:OPEN "; Qt$; "B"; Qt$;_
  3188.  ",1,"; Qt$; RealSource$
  3189. PRINT #2, "T$="; Qt$; "abcdefghijklmnopqrstuvwxyz"; Qt$;_
  3190.  ":T$=T$+UCASE$(T$)+"; Qt$; "0123456789#$"
  3191.     Prefix$ = "G" + Qt$
  3192.     Work$ = Prefix$
  3193. END IF
  3194.  
  3195. END SUB
  3196.  
  3197. SUB PrintDecoder
  3198.  
  3199. IF SmallScript THEN
  3200.     PrintLine "~" + Num2Str$(FileLength) + "~" +_
  3201.  Num2Str$(CheckSum) + "~" + "End"
  3202. ELSE
  3203.  
  3204. 'Main decoder originally reduced from 8 lines to 6 lines by Jim
  3205. Giordano
  3206. 'Thanks Jim!
  3207.  
  3208. 'Slight modifications to the 6 line decoder by Rich Geldreich
  3209. 'More modifications to the decoder to implement compressed code,
  3210. '  increased to ~7.2 lines by Victor Yiu
  3211. 'Modified again to increase speed, but at the slight expense of
  3212. ' size (3/9/93)  -VY
  3213.  
  3214. PrintLine "N=" + Num2Str$(FileLength) + ":K=255:IF LEN(C$)<>" +_
  3215.  Num2Str$(BytesOut) + " THEN ?" + Qt$ + "Bad script!" + Qt$ +_
  3216.  ":END"
  3217. PrintLine "FOR A=1 TO N:LOCATE 1:?STRING$(50/N*A,177):IF L=0"+_
  3218. " THEN GOSUB G:L=6"
  3219. PrintLine "W=T\P(6-L):GOSUB G:W=W OR T*P(L):L=L-2:B$=CHR$(W AND"+_
  3220. " K):PUT 1,,B$:NEXT"
  3221. PrintLine "?:IF C=" + Num2Str$(CheckSum) + " THEN ?" + Qt$ +_
  3222.  "Ok" + Qt$ + ":END ELSE ?" + Qt$ + "Bad checksum!" + Qt$ +_
  3223.  ":END"
  3224. PrintLine "G:I=I+1:T=INSTR(T$,MID$(C$,I,1))-1:C=(C+T)*2:C=C"+_
  3225. "\256+(C AND 255):RETURN"
  3226. PrintLine "SUB G(A$):SHARED C$:FOR Q=2 TO"+_
  3227. " 9:DO:S=INSTR(A$,CHR$(Q+38))"
  3228. PrintLine "IF S THEN A$=LEFT$(A$,S-1)+STRING$(Q,97)+MID$(A$,S+1)"
  3229. PrintLine "LOOP WHILE S:NEXT:C$=C$+A$:END SUB"
  3230. END IF
  3231.  
  3232. CLOSE
  3233.  
  3234. END SUB
  3235.  
  3236. 'Outputs one line to the output file, and opens another output file
  3237. 'if the page length is exceeded.
  3238. SUB PrintLine (A$)
  3239.  
  3240. IF NewFileFlag THEN
  3241.     LOCATE Row, Col
  3242.     PRINT "          "
  3243.  
  3244.     NewFileFlag = False
  3245.     CurrentPage = CurrentPage + 1  '<-- switched these 2 lines
  3246.  
  3247.     B$ = Num2Str$(CurrentPage)     '--> MHB
  3248.     PRINT #2, "'>> Continued on pg. "; B$
  3249.     CLOSE #2
  3250.  
  3251.     F$ = UCASE$(DestFile$ + B$ + DestExten$)
  3252.  
  3253.     PRINT "Now writing: "; F$; " ";
  3254.     Row = CSRLIN: Col = POS(0)
  3255.  
  3256.     OPEN F$ FOR OUTPUT AS #2 LEN = 8192
  3257.  
  3258.     PRINT #2, "'>> Start: pg. "; B$
  3259.     LinesOut = 1
  3260. END IF
  3261.  
  3262. TotalLinesOut = TotalLinesOut + 1
  3263.  
  3264. PRINT #2, A$
  3265.  
  3266. ' Originally, Mark hardcoded a space after each line, but I
  3267. ' had to remove it to make compression work properly... -VY
  3268.  
  3269. LinesOut = LinesOut + 1
  3270. IF LinesOut >= PageLength THEN NewFileFlag = True
  3271.  
  3272. END SUB
  3273.  
  3274. 'Adds a character to the output string.
  3275. SUB PutByte (A)
  3276. SHARED Good$
  3277. STATIC ALength
  3278.  
  3279. IF CurrentBit < 0 THEN LastOne = True
  3280.  
  3281. BytesOut = BytesOut + 1
  3282.  
  3283.     'calculate a checksum on the encoded data stream
  3284. CheckSum = (CheckSum + A) * 2
  3285. CheckSum = CheckSum \ 256 + (CheckSum AND 255)
  3286.  
  3287. IF (A = 0) AND (LastOne = False) THEN
  3288.     IF ALength = 9 THEN
  3289.         ALength = 1
  3290.         Work$ = Work$ + "/"
  3291.     ELSE
  3292.         ALength = ALength + 1
  3293.     END IF
  3294. ELSE
  3295.     SELECT CASE ALength
  3296.         CASE 0
  3297.             'translate the output character into something safe
  3298.             Work$ = Work$ + MID$(Good$, A + 1, 1)
  3299.         CASE 1
  3300.             Work$ = Work$ + "a" + MID$(Good$, A + 1, 1)
  3301.             ALength = 0
  3302.         CASE ELSE
  3303.             Work$ = Work$ + MID$(ComprChar$, ALength - 1, 1) +_
  3304.  MID$(Good$, A + 1, 1)
  3305.             ALength = 0
  3306.    END SELECT
  3307. END IF
  3308.  
  3309. IF LEN(Work$) >= LineLength THEN
  3310.     IF LEN(Work$) = LineLength THEN
  3311.         PrintLine Work$
  3312.         Work$ = Prefix$
  3313.     ELSE
  3314.         PrintLine LEFT$(Work$, LineLength)
  3315.         Work$ = Prefix$ + MID$(Work$, LineLength + 1)
  3316.     END IF
  3317. END IF
  3318.  
  3319. END SUB
  3320.  
  3321. SUB PutBytes (A)
  3322.  
  3323.     'shift the 8 bit character into the work buffer
  3324. Char = Char + A * Shift(CurrentBit)
  3325.  
  3326.     'we've got 8 more bits now
  3327. CurrentBit = CurrentBit + 8
  3328.     'write the 6 bit codes now
  3329. DO WHILE CurrentBit > 5          'have at least 6 bits left?
  3330.     PutByte (Char AND 63)        'write out the first 6 bits
  3331.     Char = Char \ 64             'shift it right 6 places
  3332.     CurrentBit = CurrentBit - 6  '6 bits less now
  3333. LOOP
  3334.  
  3335. END SUB
  3336.  
  3337. SUB Shadow (Uprow, Ltcol, Lorow, Rtcol) STATIC
  3338.  
  3339.     '*** Transparent Shadow routine for use with the
  3340.     '*** "Drawbox" SUB program by Mark H Butler
  3341.  
  3342. DEF SEG = &H40
  3343. equip = PEEK(&H10)
  3344. IF (equip AND 48) = 48 THEN
  3345.     EXIT SUB    '*** no use in doing it if it's mono, right?
  3346. ELSE
  3347.     DEF SEG = &HB800
  3348. END IF
  3349.  
  3350.     '****** use the given box dimensions to POKE a ***********
  3351.     '****** "shadow" on the right side and bottom edge *******
  3352.  
  3353. attr = 8
  3354.  
  3355. FOR Row = Uprow + 1 TO Lorow + 1    '***** right edge
  3356. ' locations.***
  3357.     FOR Col = Rtcol + 1 TO Rtcol + 2'***** make it 2 chars
  3358. ' wide.***
  3359.         offset = (Row - 1) * 160 + (Col - 1) * 2 + 1
  3360.         POKE offset, attr
  3361.     NEXT
  3362. NEXT
  3363.  
  3364. Row = Lorow + 1                    '***** now POKE along the
  3365. ' *****
  3366. FOR Col = Ltcol + 2 TO Rtcol + 2   '***** bottom edge
  3367. ' ************
  3368.     offset = (Row - 1) * 160 + (Col - 1) * 2 + 1
  3369.     POKE offset, attr
  3370. NEXT
  3371. DEF SEG
  3372.  
  3373. END SUB
  3374.  
  3375. SUB ShortCopyright
  3376.  
  3377. COLOR 14, 0
  3378. CLS
  3379.  
  3380. PRINT " PostIt! Version 6.0"
  3381. PRINT
  3382. COLOR 11
  3383. PRINT " Freeware by Rich Geldreich, 1992-1993."
  3384. PRINT " Decoder modifications by Jim Giordano."
  3385. PRINT " User interface and graphics by "
  3386. PRINT " Mark H Butler and Quinn Tyler Jackson."
  3387. PRINT " Text code wrapping by Scott Wunsch."
  3388. PRINT " Compression & new script format by Victor Yiu."
  3389. PRINT
  3390. COLOR 7
  3391.  
  3392. END SUB
  3393.  
  3394. SUB Twirl STATIC
  3395.  
  3396. LOCATE Row, Col
  3397. PRINT MID$(Proplr$, Turn + 1, 1);
  3398. Turn = (Turn + 1) AND 3
  3399.  
  3400. IF Turn = 0 THEN
  3401.     PRINT USING " ###%"; 100& * CurrentByte \ FileLength;
  3402. END IF
  3403.  
  3404. END SUB
  3405.  
  3406. SUB WarningScreen
  3407.  
  3408. ' I felt this screen was appropriate, since some users have
  3409. ' abused this wonderful utility!  Shame.... <qtj>
  3410. '----
  3411. ' Unfortunately Quinn old friend I think that has proved to be
  3412. ' too true in some cases ...but... we *can* make it look as
  3413. ' friendly as possible with a little text mode window magic `eh?
  3414. ' --> MHB ;^]
  3415.  
  3416. PCOPY frontpage, backpage
  3417. COLOR 14, 6
  3418. DrawBox 3, 8, 22, 72, True
  3419. Shadow 3, 8, 22, 72
  3420.  
  3421. LOCATE 4, 11: PRINT "NOTE:"
  3422. LOCATE , 10: PRINT "Some echo participants feel that posting"+_
  3423. " binary files in text"
  3424. LOCATE , 10: PRINT "format leads to anarchy.  Postit!,  in all"+_
  3425. " of its versions is"
  3426. LOCATE , 10: PRINT "a powerful tool for exchanging information"+_
  3427. " over networks such"
  3428. LOCATE , 10: PRINT "as Fidonet.  Before you use this software to"+_
  3429. " post anything in"
  3430. LOCATE , 10: PRINT "any network's echo areas, consider these"+_
  3431. " points:"
  3432. PRINT
  3433. LOCATE , 10: PRINT "1) Only users  with Microsoft's QBASIC or "+_
  3434. " QuickBASIC will be"
  3435. LOCATE , 10: PRINT "   able to convert the files back into their"+_
  3436. " binary format."
  3437. PRINT
  3438. LOCATE , 10: PRINT "2) Binary files that are converted to text"+_
  3439. " should be ON TOPIC"
  3440. LOCATE , 10: PRINT "   in order  that users of  the particular"+_
  3441. " echo  will benefit"
  3442. LOCATE , 10: PRINT "   from the post. For example: it would not"+_
  3443. " be appropriate at"
  3444. LOCATE , 10: PRINT "   all to post an executable file  without"+_
  3445. " it's corresponding"
  3446. LOCATE , 10: PRINT "   source code in the Fidonet QUIK_BAS echo."
  3447. PRINT
  3448. LOCATE , 10: PRINT "  This of course  only applies to the binary"+_
  3449. "  posting portion"
  3450. LOCATE , 10: PRINT " of PostIt!.  The code wrapper is much less"+_
  3451. " controversial :)."
  3452.  
  3453. Delay 5
  3454. COLOR 11, 1
  3455. LOCATE 24, 20: PRINT "(Hit any key to continue with Postit!)";
  3456. DO UNTIL LEN(INKEY$): LOOP
  3457.  
  3458. PCOPY backpage, frontpage
  3459.  
  3460. END SUB
  3461.  
  3462. '
  3463.  
  3464.  
  3465.  
  3466.  
  3467. Msg #:  651                       QUIKBAS Subboard
  3468.  From:  TIM BENNETT               Sent: 04-05-93 10:17
  3469.    To:  ALL                       Rcvd: -NO-
  3470.    Re:  A USEFUL FUNCTION
  3471.  
  3472. DECLARE FUNCTION monstring$ (cash AS SINGLE, pad%)
  3473.  
  3474. ' This function takes a number up to 99999.99 and returns
  3475. ' a string in the form of -Ninety Nine Thousand Nine Hundred Ninety Nine   '
  3476. ' Dollars and 99/100. If pad% is TRUE then the
  3477. ' string is centered in a string of astricks and will be 72
  3478. ' characters long.  Please don't make fun of my variable names, I just threw
  3479. ' this together because I needed it at the time
  3480. ' You are free to use or modify this in any way you wish.
  3481. ' Lines with the underscore character should be joined with the one below.
  3482.  
  3483.  
  3484. DEFSNG A-Z
  3485. FUNCTION monstring$ (cash AS SINGLE, pad%)
  3486. IF cash < 0 THEN
  3487. monstring$ = ""
  3488. EXIT FUNCTION
  3489. endif
  3490. DIM one$(10), ten$(9), teen$(9)
  3491. one$(0) = "": one$(1) = "One ": one$(2) = "Two ": one$(3) = "Three "
  3492. one$(4) = "Four ": one$(5) = "Five "6: one$(6) = "Six ": one$(7) = "Seven "
  3493. one$(8) = "Eight ": one$(9) = "Nine ": one$(10) = "Ten "
  3494. ten$(1) = "Ten ": ten$(2) = "Twenty ": ten$(3) = "Thirty ": ten$(4) =
  3495. "Forty "
  3496. ten$(5) = "Fifty ": ten$(6) = "Sixty ": ten$(7) = "Seventy ":
  3497. ten$(8) = "Eighty ":ten$(9) = "Ninety "
  3498.  
  3499. teen$(1) = "Eleven ": teen$(2) = "Twelve ": teen$(3) = "Thirteen "
  3500. teen$(4) = "Fourteen ": teen$(5) = "Fifteen ": teen$(6) = "Sixteen "
  3501. teen$(7) = "Seventeen ": teen$(8) = "Eighteen ": teen$(9) = "Nineteen "
  3502.  
  3503. cccash$ = LTRIM$(STR$(cash))
  3504. ll! = LEN(cccash$)
  3505. lw! = INSTR(cccash$, ".")
  3506. IF ll! - lw! < 2 THEN cccash$ = cccash$ + "0"
  3507. IF lw! = 0 THEN
  3508. cccash$ = cccash$ + ".00": lw! = ll!
  3509. ELSE
  3510. lw! = lw! - 1
  3511. END IF
  3512. IF lw! > 5 THEN
  3513. monstring$ = STRING$(72, 32)
  3514. EXIT FUNCTION
  3515. END IF
  3516. ccccash$ = LEFT$(cccash$, lw!)
  3517. ccash! = VAL(LEFT$(cccash$, lw!))
  3518. SELECT CASE lw!
  3519.     CASE 1
  3520.         temp$ = one$(ccash!)
  3521.     CASE 2
  3522.         SELECT CASE ccash!
  3523.             CASE 11 TO 19
  3524.             temp$ = teen$(ccash! - 10)
  3525.             CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3526.             temp$ = ten$(ccash! \ 10)
  3527.             CASE ELSE
  3528.             temp$ = ten$(ccash! \ 10) + one$(VAL(RIGHT$(STR$(ccash!),1)))
  3529.             END SELECT
  3530.     CASE 3
  3531.         SELECT CASE ccash!
  3532.             CASE 100, 200, 300, 400, 500, 600, 700, 800, 900
  3533.             temp$ = one$(ccash! \ 100) + "Hundred "
  3534.             CASE ELSE
  3535.             temp$ = one$(ccash! \ 100) + "Hundred "
  3536.             crash! = VAL(RIGHT$(ccccash$, 2))
  3537.                 SELECT CASE crash!
  3538.                 CASE 0 TO 10
  3539.                     temp$ = temp$ + one$(crash!)
  3540.                 CASE 11 TO 19
  3541.                     temp$ = teen$(crash! - 10)
  3542.                 CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3543.                     temp$ = temp$ + ten$(crash! \ 10)
  3544.                 CASE ELSE
  3545.                     temp$ = temp$ + ten$(crash! \ 10) + one$(VAL_
  3546.                      (RIGHT$(STR$(crash!), 1)))
  3547.                 END SELECT
  3548.             END SELECT
  3549.     CASE 4
  3550.         SELECT CASE ccash!
  3551.             CASE 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000
  3552.                 temp$ = one$(ccash! \ 1000) + "Thousand "
  3553.             CASE 1100 TO 1999
  3554.                 temp$ = teen$(ccash! \ 100 - 10) + "Hundred "
  3555.                 crash! = VAL(RIGHT$(ccccash$, 2))
  3556.                 SELECT CASE crash!
  3557.                     CASE 0 TO 10
  3558.                         temp$ = temp$ + one$(crash!)
  3559.                     CASE 11 TO 19
  3560.                         temp$ = teen$(crash! - 10)
  3561.                     CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3562.                         temp$ = temp$ + ten$(crash! \ 10)
  3563.                     CASE ELSE
  3564.                         temp$ = temp$ + ten$(crash! \ 10) + one$(VAL_
  3565.                          (RIGHT$(STR$(crash!), 1)))
  3566.                 END SELECT
  3567.             CASE 2001 TO 9999
  3568.                 part1 = VAL(LEFT$(ccccash$, 2))
  3569.                 crash! = VAL(RIGHT$(ccccash$, 2))
  3570.                 SELECT CASE part1
  3571.                     CASE 20, 30, 40, 50, 60, 70, 80, 90
  3572.                         temp$ = one$(part1 \ 10) + "Thousand "
  3573.                     CASE ELSE
  3574.                     temp$ = ten$(part1 \ 10) + one$(VAL(MID$(_
  3575.                       ccccash$, 2, 1))) + "Hundred "
  3576.                     END SELECT
  3577.                 SELECT CASE crash!
  3578.                     CASE 0 TO 10
  3579.                         temp$ = temp$ + one$(crash!)
  3580.                     CASE 11 TO 19
  3581.                         temp$ = teen$(crash! - 10)
  3582.                     CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3583.                         temp$ = temp$ + ten$(crash! \ 10)
  3584.                     CASE ELSE
  3585.                         temp$ = temp$ + ten$(crash! \ 10) + one$(VAL_
  3586.                           (RIGHT$(STR$(crash!), 1)))
  3587.                 END SELECT
  3588.             CASE ELSE
  3589.             END SELECT
  3590.     CASE 5
  3591.         part1 = VAL(LEFT$(ccccash$, 2))
  3592.         part2 = VAL(MID$(ccccash$, 3, 1))
  3593.         crash! = VAL(RIGHT$(ccccash$, 2))
  3594.         SELECT CASE part1
  3595.             CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3596.                 temp$ = ten$(part1 \ 10) + "Thousand "
  3597.             CASE 11 TO 19
  3598.                 temp$ = teen$(part1 - 10) + "Thousand "
  3599.             CASE ELSE
  3600.                 temp$ = ten$(part1 \ 10) + one$(VAL_
  3601.                   (RIGHT$(STR$(part1), 1))) + "Thousand "
  3602.         END SELECT
  3603.         SELECT CASE part2
  3604.             CASE 0
  3605.             temp$ = temp$ + ""
  3606.             CASE 1 TO 9
  3607.             temp$ = temp$ + one$(part2) + "Hundred "
  3608.             CASE ELSE
  3609.          END SELECT
  3610.          SELECT CASE crash!
  3611.             CASE 0 TO 10
  3612.                 temp$ = temp$ + one$(crash!)
  3613.             CASE 11 TO 19
  3614.                 temp$ = temp$ + teen$(crash! - 10)
  3615.             CASE 10, 20, 30, 40, 50, 60, 70, 80, 90
  3616.                 temp$ = temp$ + ten$(crash! \ 10)
  3617.             CASE ELSE
  3618.                 temp$ = temp$ + ten$(crash! \ 10) + one$(VAL_
  3619.                   (RIGHT$(STR$(crash!), 1)))
  3620.             END SELECT
  3621.     CASE ELSE
  3622. END SELECT
  3623. IF temp$ = "One " THEN ext$ = "" ELSE ext$ = "s"
  3624. IF temp$ = "" THEN temp$ = "Zero ": ext$ = "s"
  3625. temp$ = temp$ + "Dollar" + ext$ + " and " + RIGHT$(cccash$, 2) + "/100"
  3626. zz% = LEN(temp$)
  3627. zzy% = zz% \ 2
  3628. zzx% = zz% - zzy%
  3629. IF pad% <> 0 THEN
  3630. pad$ = STRING$(72, "*")
  3631. FOR x = 2 TO 72 STEP 4
  3632. MID$(pad$, x, 2) = "  "
  3633. NEXT x
  3634. MID$(pad$, 36 - zzy%, zz%) = temp$
  3635. monstring$ = pad$
  3636. ELSE
  3637. monstring$ = temp$
  3638. END IF
  3639. END FUNCTION
  3640.  
  3641. '
  3642.  
  3643.  
  3644. Msg #:  772                       QUIKBAS Subboard
  3645.  From:  EARL MONTGOMERY           Sent: 04-06-93 21:52
  3646.    To:  FRED DISANO               Rcvd: -NO-
  3647.    Re:  ROTATE PALETTES (COLORS)
  3648.  
  3649. 'Fred, here is something that should get you started. If you get
  3650. 'a Plasma type program written please post it. I would love to
  3651. 'see it!
  3652. 'Remarks: The first out sets up the VGA Video to read the color
  3653. 'value RGB from color 2. These are stored in variables R1,R2
  3654. 'and R3.
  3655. 'The next set of OUTS puts the RGB values from color 2 into
  3656. 'Color 1.
  3657. 'The two LINE statements proves it works. I am sure you can
  3658. 'take it from here and accomplish what you want to do.
  3659. 'Good Luck
  3660. 'Earl
  3661. DEFINT A-Z
  3662. SCREEN 13
  3663. LINE (0, 10)-(100, 10), 1  'COLOR 1
  3664. LOCATE 2, 20: PRINT "Color 1"
  3665. C = 1: D = C + 1
  3666. sleep(5) 'Needed to let you see the change that occurs.
  3667. OUT &H3C7, D   'D starts out as color 2
  3668. r1 = INP(&H3C9)
  3669. r2 = INP(&H3C9)
  3670. r3 = INP(&H3C9)
  3671. OUT &H3C8, C  'C starts out as color 1
  3672. OUT &H3C9, r1
  3673. OUT &H3C9, r2
  3674. OUT &H3C9, r3 'At this point Color 1 becomes Color 2
  3675. LINE (0, 42)-(100, 42), 2
  3676. LOCATE 6, 20: PRINT "Color 2"
  3677. DO
  3678. LOOP
  3679. ' I hope I got this right! I'm dead tired and going to bed!
  3680.  
  3681.  
  3682. 'Fred, if you have a copy of my VGACLIP TSR, use it to capture
  3683. 'a plasma screen (320*200*256)
  3684. 'Change the capture file name if necessary to VGASCR02.cap
  3685. 'Then put it in the QB directory and run this program
  3686. 'This is NOT repeat NOT what you want to do but it might
  3687. 'give you some ideas. Play around with the variables and
  3688. 'see what you come up with.
  3689. SCREEN 0: CLS : RANDOMIZE TIMER
  3690. DEFINT A-Z
  3691. N$ = "VGASCR02.cap"
  3692. SCREEN 13
  3693. OUT &H3C8, 0
  3694. FOR x = 0 TO 767
  3695. OUT &H3C9, 0
  3696. NEXT
  3697. DEF SEG = &HA000
  3698. BLOAD N$, 0
  3699. DEF SEG = &HA000 + 4000
  3700. OUT &H3C8, 0
  3701. FOR x = 0 TO 767
  3702. P = PEEK(x)
  3703. OUT &H3C9, P
  3704. NEXT
  3705. begin:
  3706. r1 = 1: r2 = 1: r3 = 1    'Change these around!
  3707. FOR x = 255 TO 1 STEP -1  'Change this loop around!
  3708. r1 = r1 + RND * 1         'Change the rnd(s) around!
  3709. r2 = r2 + RND * 2
  3710. r3 = r3 + RND * 3
  3711. OUT &H3C8, x
  3712. OUT &H3C9, r1
  3713. FOR delay = 0 TO 1500: NEXT    'Change the delays to best suit your
  3714.                                'system
  3715. OUT &H3C9, r2
  3716. FOR delay = 0 TO 1500: NEXT
  3717. OUT &H3C9, r3
  3718. NEXT
  3719. GOTO begin
  3720. DO
  3721. LOOP
  3722.  
  3723.  
  3724. '
  3725.  
  3726.  
  3727.  
  3728. Msg #:  874                       QUIKBAS Subboard
  3729.  From:  DOUGLAS LUSHER            Sent: 04-08-93 09:28
  3730.    To:  TOM CARROLL               Rcvd: -NO-
  3731.    Re:  UNIX TIMESTAMP
  3732.  
  3733. TC>Sure, and I'd also like to know if you can figure the day of the week by
  3734. TC>doing this:
  3735.  
  3736. TC>WeekDay = TotalDays& MOD 7
  3737. TC>SELECT CASE WeekDay
  3738. TC>   CASE 0: Today$ = "Thursday"
  3739. TC>   CASE 1: Today$ = "Wednesday"
  3740. TC>   CASE 2: Today$ = "Tuesday"
  3741. TC>   CASE 3: Today$ = "Monday"
  3742. TC>   CASE 4: Today$ = "Sunday"
  3743. TC>   CASE 5: Today$ = "Saturday"
  3744. TC>   CASE 6: Today$ = "Friday"
  3745. TC>END SELECT
  3746.  
  3747. Sorry, I can't help you with your question about the UNIX time-stamp,
  3748. but here's code to figure the day of the week:
  3749.  
  3750. FUNCTION DOW% (InDate$)
  3751. 'returns a value representing the day of the week (0 = Saturday, 1 = Sunday,
  3752. '2 = Monday, etc) for the date string supplied in the form "MM-DD-YYYY"
  3753.  
  3754. Month% = (ASC(MID$(InDate$, 1)) - 48) * 10
  3755. Month% = Month% + (ASC(MID$(InDate$, 2)) - 48)
  3756. Day% = (ASC(MID$(InDate$, 4)) - 48) * 10
  3757. Day% = Day% + (ASC(MID$(InDate$, 5)) - 48)
  3758. Year% = (ASC(MID$(InDate$, 7)) - 48) * 1000
  3759. Year% = Year% + (ASC(MID$(InDate$, 8)) - 48) * 100
  3760. Year% = Year% + (ASC(MID$(InDate$, 9)) - 48) * 10
  3761. Year% = Year% + (ASC(MID$(InDate$, 10)) - 48)
  3762. Year% = Year% + (Month% < 3)
  3763. Temp& = (Year% * 365&) + (Year% \ 4) - (Year% \ 100) + (Year% \ 400)
  3764.  
  3765. SELECT CASE Month%
  3766.   CASE 1: Temp& = Temp& + 365
  3767.   CASE 2: Temp& = Temp& + 396
  3768.   CASE 3: Temp& = Temp& + 59
  3769.   CASE 4: Temp& = Temp& + 90
  3770.   CASE 5: Temp& = Temp& + 120
  3771.   CASE 6: Temp& = Temp& + 151
  3772.   CASE 7: Temp& = Temp& + 181
  3773.   CASE 8: Temp& = Temp& + 212
  3774.   CASE 9: Temp& = Temp& + 243
  3775.   CASE 10: Temp& = Temp& + 273
  3776.   CASE 11: Temp& = Temp& + 304
  3777.   CASE 12: Temp& = Temp& + 334
  3778. END SELECT
  3779.  
  3780. DOW% = (Temp& + Day%) MOD 7
  3781.  
  3782. END FUNCTION
  3783.  
  3784. '
  3785.  
  3786.  
  3787. Msg #:  875                       QUIKBAS Subboard
  3788.  From:  KEITH WATKINS             Sent: 04-08-93 11:39
  3789.    To:  ARTHUR SHIPKOWSKI         Rcvd: -NO-
  3790.    Re:  C TO BASIC
  3791.  
  3792. CLS:?STRING$(50,178):DEFINT A-Z 'Created by PostIt! 6.0
  3793. FOR A=0 TO 6:P(A)=2^A:NEXT:OPEN "B",1,"CSTUFF.ZIP
  3794. T$="abcdefghijklmnopqrstuvwxyz":T$=T$+UCASE$(T$)+"0123456789#$
  3795. G"qT0aeO*GbaqSJvCrKedGBbC*cf(Wb*d9etUq0td1GabiXiuuHn3GwIAUnpfyGet
  3796. G"quX2B59fAzz7BVlidRClliPlAg#V7Bb5CPRCR7yPBDIEpxq62YwwYe8Q6f17Zww
  3797. G"6csYgw6gwqAw5#22cYPM2Z62WYwqo23Yw2wg13P9TUX6DAsEpxx2qfsfITL3Yzy
  3798. G"LXibzANZ2S2JR5DyUwlh6B6RDlz8UBhO11P49Bnt172sx7W9szDBRtXUya$bPmM
  3799. G"E$w5qExSP5ETCZJZZ2W0L7wWtPWSX9D1DDplAiVdL9HNU5foh1rjCddqv$Dxg41
  3800. G"UnnaDo3uypNkOhgM1OKkGVzJ6HVUUb5fB1ePAq751sxen7UmWAlP6#9zbPCK699
  3801. G"JgPUzlzeQKmhRmY3nhP91XXimNxgXherFoJ5KSIvotZxYEQHZ8piBBAaZMB1G8o
  3802. G"7VDtss2w4ONNuUhJ1R2vj9dtu7SW9f57YSNR5UmsDDPZBwNx6wgLvVVeQrncG4a
  3803. G"7aTdTs7MRUB7BC6j8k9TCjtxjsId5XD9YINGqDwS9wD2Xqib5Ebjic#FPkIcSGj
  3804. G"rHGx1CX7A2MNIuRYx0$A9tUVCedYDWFdyYEcYtkZtCgmo3dYy6I5ql0ycYwWCxM
  3805. G"Ueg4bezbZybh8yMgimdtYkJCJx60Fji6pqDk9xM32kM0QbjB#RXFQ#ZCcJ4v0B8
  3806. G"89oS7a6DF3XxgMJW8YIPf7wUycdfzIZcXpG1HnnRXdNc35MS9ljJ5n3mg5pLy8M
  3807. G"PgBnrpb5rY$fB7BnMZSRSWPq66QNYq2lBAYtR32vPlh6tzcUHgewfrWvO$FrYvP
  3808. G"Lri0JdibgldAov#f73KHziTSzw21JKbIwgew8nzUAywgXrAFFGLn9Enlde5BmcJ
  3809. G"EUXqziTSqXQ0D0L1T0z8IOD6KgA4SmGPmzH0Xb72Nri1Ynm2f0UEvBObb3TYU89
  3810. G"L7MDbCww8iCQn0wgvOtSSjKaYVfUJLnidHLPUE1P#xqKQeLEojBiVkEtNePtgyb
  3811. G"kCp1YqGxRh7AwgeRlC0Udcz3Pl331nmxHm4gliKfGzSqkl8Xql1YXkgHH4ndS6d
  3812. G"duLyzGuPhklZg1P275lfldHM5UToyMvsnuPy8LRGhw7SYwLjwsdPMrLLQyX9g8V
  3813. G"S#slvSESWrPB7#f9KvDS2X2OexfDKrJJCJMNJXM$CoM$C4CCA1CoMWq#fPAthgD
  3814. G"L1u10XkNZUJb5rc6BZoshcevNw9WzBXdbRdbvBd7#oS#GYu3kkKvCsDEkCHwyYS
  3815. G"LYYSfGZ9DBYLwrgjP35XNxl3DunbBSNJh1L7edYfNjToL5oQgrBQEJ1GFgo3m3S
  3816. G"cIxD075QJfxOGmmGXazqb7fIWXXT6i3VrxTQMGYbciJAmusHTDbYqk4dzDmG2E6
  3817. G"A26Oa#nz2ADkIAqrXhidSLHwALMnBazKOOS4PazGMqoqgJ7ql1KI7qq3II7qdTk
  3818. G"wxw#bhwvZAGXVRXDqSm4ov9GXTxP7IAWPT32bnqhR7r1Kjy78eezulXobLLmgOP
  3819. G"obKPtvPw1I2JRhIK2gMvsHBwZ2c50Yzs1nQ0x2yYe0$DDedZiX#TFb59DNJ2vd0
  3820. G"icE70Ns1Ia50z5wTMjugHc2xw0B30JxCZk8WGnn7QDEk$rJU6U5wS4QdLgo8yhl
  3821. G"Mybzm3XWYXilxYVxBAHte#Co#4W9W7ZjcR6hNsC1ifviY4Q#zofE3SJWq#AMADX
  3822. G"7Jf2fRD$Mx71zeWRGI1075G#GCkPPDdmPqD0UmbLiRe5YvkzXooZzkAK4UAmayf
  3823. G"ByvlljcmkSSq6ragf3vltmFeZJemgVDOVMkVp07Oeg18mhmieNJfK7LyzPGBqNM
  3824. G"orWh7r4eVLwf6wrxz8Hd0FyGJ9nnOyfPfnOePXdT8B2p65$TqEzx6geyl7a3ipM
  3825. G"qVEe2WRehL98ykdFQmjSDAu8DB64IhnSi0ZbhrGaBWaTriu5ILeUKPVWeJdCHsf
  3826. G"AfduWjwGd5ZD0KPZjokplob$yUx1Jg3TTUOUPXmoTNRTD4wt2fGDv54Z1fEwWWw
  3827. G"1e8de6mmmqanP3SPZUDb8kpWneF0AO0E6c9cbWGTIu52R5kkDHbsGkvOYk7Juug
  3828. G"qAXv5$CR3uMDDh5SnOmIu5ZYgbKDvvY72uOJBSGt9bJLD$#Kb5aT#eVfcaRBtgS
  3829. G"4nBDcv30uAWcmmVAkdAqzDqpbecGhorWzagy3HoSaAndoEHuutNWWKNcqAeMSdn
  3830. G"WYCMJeWbd6xnsvLoo4ZJjo#zdflHpH3DTZ5JpuOE04bR5h#8TjEaSYuqOb$IXhA
  3831. G"yPo70PmvOb5itbJZgyMjmb30MqO8xvtElVtaWWrDr0P6#QFr9Chhjm5yvwpoDkd
  3832. G"b9otycoT82wgP7NX2nSPwk0RtJpMwIeRnlAJLAK#CR4SlanC90ISlm0ObrcqWoh
  3833. G"yhCrGO$YRdAbKDOdJSdG2RdO1ceG0Rd6xuI0qT0aeO*Gba44KvCXuTqzdcx)0Fe
  3834. G"(qb*d9etUGudceGeJqrf2CdAjQ528uGbsmbrfBVL3$LQeKGCOpLPUejgVcUMSLD
  3835. G"UJvUPvmfVbPytRBdRCZlih7BzlBl7yPBAFRBbPzttYlI3VvUTnS0fKXy9VHki4n
  3836. G"iZ5lNjmFjoVjiB6vg2nAAL7C2EB3Yu869Z7PkFrXZruTA$TB2Ft0N60Ns1Qo1Im
  3837. G"9i4v6B5whSvGlrBzdlzb5E#Nb1R5rWAqkN6vQRSEJsZmnR5IQ1SnVPeevlw$hlA
  3838. G"a76P72sN39D83mGL9eKNuMNaTtqo10EM0UDPmbPqC7Ufm3LPlHbwXqknlygl4Gh
  3839. G"Z0aHzyswt3YIx6yKz9hOoL#lZBBftA1GKTPDo8NO$mOUy#IEJNV3HDhqV77o#Y6
  3840. G"rMwZcc8SQip9mpf3zSWPoVKmHy#0nVWTmkzk$PHI$0WnSNTmntNMLGLpzDDtASp
  3841. G"d4IGzKp3b#Dy8MFoXr5zXt49qyB919kZwoYY6wYu2LtagW10b1$9m0IMR#Jc9is
  3842. G"Wn4sf4wzFKABajUB#336nLzx3bQJnLyKnjzfRCKDfbljJtSddMVd7CIhNfIFuXo
  3843. G"mT5EoM7YLofVFRzkYCYyE7Oa6e9eKhj$xaEFRXCMDLfIEKUUAUmK9YMMg7dYW6M
  3844. G"56UaZyZM#CbHQNi4k0$ViViz4wM5MfApOCaJLbnNk$I9BYWmKw2ml76rYarldcF
  3845. G"MnzUAywgXrAFFGLn9Enlde5MQPyx35gdLH0YY2#ghnDzOT24vr70P3QHZYaMYKf
  3846. G"shhHEFgHul3Wyxq76LB8UH1AC3k7sYOC3SlGZYIOUNJAdTLrvRhlBcjG8BH7yzd
  3847. G"YqyzQRxWvD8Ii1SXVQKnKxfVPtO9sEBw5#22G7jwgcew9yxZYGyDHJ2Dqi7EY#2
  3848. G"76gMRqgCJfeYcWmwiLf#yRRCLJvmcdXBgy1hgTqILbsLEOcckEQBjXE$3CP10zz
  3849. G"i0m3T1bZSsQTSn#r675gw74MpDFJC1PrAi1mQSuPVgeVb$lRV0sfRhlCu62UFrp
  3850. G"zvhRDSnkXvrhz04P0O55yIFFhNJ5phohNwnNJjmKFrQ20HrxznvnDSY5S7yqEKG
  3851. G"#2SJ0Har1PvpC2w8qW6qq12WUVtqmZKDRqHSItQZtHl0ctMTuwMTaCUVBtU0kYi
  3852. G"j9opsmA5UJQjieqBMb5IZKwNYChvJOnvVXAWpdNBgG0oFv##SZvhlUqbzyaJbYG
  3853. G"c2leHJJFdYZ#gD1QAckhiGmQXqjf22fidPG$EitjE6nBDua$MmBTofrnOO4dKb2
  3854. G"YqlTsZAsRCDpkklEkqgOjKdKX4o0snP4oe0TO4o0qRI1LLFWHv1Sgy87ACheldU
  3855. G"tvpyC7v6UOgCA7TDqd0X6Eunzc2opHZjG6tqzjJbAQtaz6uvQvTO946XLDre75K
  3856. G"JN2SMTLSHaBiMGj91hMmb9FxhXWwNvT#liVV7C0UAGgek162mqdVzRtk6Q#f1B5
  3857. G"2gcAanZRiObAb00b9e6SaEIIGtlny3bjnaTMbNzIIA6eggzsHIgbKDGHkZzooqd
  3858. G"g0V4DQmH4GppM4i1gklopH3DTZjjafQhg4bR5hObRpaWImRUfIBtqqWJ6StNYuH
  3859. G"gKJmLgFR1ktycc1MqO8x9jVL3jay4OUi6uDF1VOEUJJeMrEkRhtClD#9otycar7
  3860. G"TTms3pdvCZU9BOnA4057XCjsS2SOnl1i95wXzxaA4o1ISleGJgeVoWohyhC740F
  3861. G"51bTaYo0Hr2bq71b0Uqdi96G#fLiyp23KeXHUa6VnVucLidH8jZhHO2PxBzQurE
  3862. G"ogrG6q2HdXXOXq5oiiUcYPqTQdUTBFZfiBCLgWNoxCtNwvMY0umLq1Ilm8WsgUs
  3863. G"X12470qvZJqrr9S5dGKn6ShtfiAy4OO8acUoGWW0LhWryCWFDajQJKObEHwS3H1
  3864. G"HhobkoCSomcGOPJ1HjhSGI8SomBgrBEwhMzd75vCjNlAiQQXGb2XDmc9LDSyn2V
  3865. G"YtbmGWD6kk8Raycza5A4hGgqT0aeO*GbayxrRaHPzXZDag)uQ*c*mfuwpvfvUGu
  3866. G"dceGeJqrf2CdAjQ528uGbsmbrfBVL3$LQeKGKTHnVVTU01LOj5niJ5lV5lXjoq#
  3867. G"n7BLlijBzPBytlBbjCd7zlZYVztRBtlDt7BDZ2Bv#YgQGGRhH1TU3nnOyfPfnOe
  3868. G"5#ByPmkEGT32WI302262wq6MH3ITmoRFRzbjAlByjZ77ZoxqyS$M7pTzoJi49CP
  3869. G"RCR7yPZ595c3Yog037z6fZ#yrByLd3ubpvHXK7i6uS7HLTYP6ppQVlRBPd76Ysw
  3870. G"qa#IO60ww2s27MwYsx0q3Q0$6625M2Z6gVpPzGNChDVi2tQrHI5iKFp232MWUww
  3871. G"DoIG$5GLB6SVP$kz9yCYok8Zf8EkOp9lsMj#Mo0hpzeFhMIHuWJNCB25eMQ0NVf
  3872. G"e3LUoRRbjrfAqNArb5p$5psM33DSLH2CoStlldorDtx2w2DKwqACnDQZbrdhAFy
  3873.  
  3874. G"cYw4hPgZGN9JGW3c5LDPBqqRlI30Pn3SH8y0BYYIhW8Dli#B4Hlz3I5dUdgeVdB
  3875. G"DzlDeVRbulnabk*e(LpzfxKB0QW4G*0c)q*WqpXumUymU4nIrn6ObkibGyHmeeJ
  3876. G"HnG4fJjIbHjr0iqjmr8iYiIpHmrulPjIxPJKqfbeHjaHJ5nSjgdSG6OHT8Lb0HU
  3877. G"0fObeSjm55n1Ho6eHevb1eMLbpLzM00LWKGQrLnKHSjnUznUiPLjItHk6ig2yg4
  3878. G"Gg40MqLfhfToLfSPQIzmLrTVeHaulnabk*y(rWzfxyigvEvhk)Whb(G*WqpXumU
  3879. G"8Kqk9(smajvyZj4KJA7XuNU9rcgeWe0uU9wEFaJqaAWX#w2gtxow5I4d8S30PcY
  3880. G"H6weNaK$ZmLPjvOdnOPeXfy57SmzlorSbo#qhWHA1BAzPG8gKOhvQpTQqnHd9Pm
  3881. G"nMFLQffRuLajprlAb$krdkvdkbiwlWZ70Pu9FvOtDQdyy$GKKKunRqTOt5#lQqq
  3882. G"2tGZp1S2uHWFqZu2LiM27rkYh4ajyansYATbybnyaXsYQcb4bpyabqYcDpctyap
  3883. G"qYoilmazyddOOswpVbv4cdOp1KqEb#$b#Fc#FbAvo3aZFGbuGcmaj9anGfnGaNX
  3884. G"MeGk8RFnmB5PBDNBzjtv$xllEtlDK6$QzVRCo#YGSdNJ3T01SaSJWgdC7OTSHLS
  3885. G"c#WHHO2GFLoEpBlRGBCyvAaJmJgk$RZLUYDSWnVa8RWEHaGkpzfRCfCKdlsdy7z
  3886. G"Cd8AUrhlAxd4VwacxyBHI2NByzBBfmRdReda6Hfl5HDyuYVugNbS92gM1oLMsRd
  3887. G"5g7n7BHZX#1H0C5bOBsak4BdsetaJx0bm6G2dYhYxWiqg0jiKgG3waYbCcsG11w
  3888. G"ZjYWehHwLHixGunGoeuMN4Evxm7XfBTMgxVQvZlN8FMFqRMWwc6tu0Rra2qcY$$
  3889. G"BqbEW3wN28PXVNHe0#$hyc1ITUM1SLvUhKG6$$b6$t70b9nkoMApIg$B4hWrtpi
  3890. G"X#eBu#NyR6$fcD6oW0BbSDgGnobvBasMuGLLtzpZzPvfiZfPvjiX$yNzEcTQdjU
  3891. G"b70135zcQAVhWtXAkh5a0QfKNGEfJ9afGoIX1nPXi2LPjpUbWY6$TR$eE#f1Rwc
  3892. G"Aa$2UAsg#sotHREqA1bs8oK$eVbd7hyyxGCEdvTuVwLQM2G7e0FQQ$mvTlGQMMk
  3893. G"f7bOiRJympAfqsgfzJwjJTz2WDp4fW97J7biFCJQVJJ4ThXk#i#0LM$Fr$G9R#r
  3894. G"kFutDeN4Ezm22f1D6C6p$$NiNBsADFTkcjoEgEMNMOSBM6AKpMHN5r1QhK4o54j
  3895. G"UsCtxeJ9FmSRtoZ8yeU7IW9veUNHWDlyTlHWVbg7hyytiTUescQNdWPiKOryobL
  3896. G"rfU9bqjpbuY0eHi$wiYEaiYOYM0Hamif7py3QIDiumpcfZLqX8jumNcfZRqXClu
  3897. G"m$cfZXqXMBOf3$$$IsOrIBag5#W4Le6g4fcDd4y8PCgtJEVU3KJUUOJTHDPnSZS
  3898. G"HDJnSdSHDDnStRHDxnSJQHDrnSZPHDlnShj14iYl6fs5rUGC2$JUZ2jP95OSpMH
  3899. G"9UmSFLH9OmSVKH9ImS$JH9CmSpJH9wmSFIH9qmSZHK#jK0oeu2zyNidMXrgEEKb
  3900. G"zj4amkKbAfEtqReYW0Jm4gGmqhM40JHmaEd8MOkwFqX#GnXBA$HNrlb8mSuLZQa
  3901. G"pNtLBnpW6ukB4uQgoLAfOuivGsrzCk1VMYtRu1w6iUWyAoLft$UIBtaUraOymhb
  3902. G"WuDhcRkJd(ZdjaJlafjaVlaST#q6Db8ha5ANAaIsa#AaMsa#BacJuLbymby9b4m
  3903. G"#SoaNAZWaUJ8dr3nzadkazzafYHEz8hG4mGefG#OwmD3ie0uFapkaHAaOfUvdys
  3904. G"bixdqyVyditbyAd4tb4Fd4ubyK0ema3CaZsdpxRa80bO05whqUcWzhWUcWChqVC
  3905. G"2hWVcWIhqWcWLhaf3JEafZCFaQfU3dyBbaDA4CKoaD1ouGYjVwGZrtFbwxassbw
  3906. G"vqlkQ86uaprylZteOhGNixapraTIg21u0a9bu08eu0aA7hzL1JpH3E9JJrozMN5
  3907. G"xck4oQZ9c5gCbbf85mS3MH9ZmSlg3WzPB3kk7sXnCtm2rkNU8bqFiIUkcqB$jIU
  3908. G"0l0MGMES5XMuYratMEimf0e4AwhV2wfaPlBwzc4KDc4KH3aozyQgROHekod1C2N
  3909. G"0CgC#naYfWVbCa61VM8L3yoD6nZlhDAMBDR2qMdm#K3lLuX62WJQHDrnS3PH9mb
  3910. G"ehsEpXnKYEGuE8Se93if2m07xHEpi07#iB$fd7PyyFed7EyyxdPFeO3pGYMB8#d
  3911. G"Qt6UbEys8snsb#aEyItcGGtTaQZWtef8c2JfHEfP8DKnTH7Zz9izTa3dhVfiFbO
  3912. G"xfyFbizf4FbOAfamRbSajmavSayOSMfOHbiPfaS5QwGjgGWwGrgGgxanXa8NYau
  3913. G"8cSYae$c0sAPf4Le7hyMsP9aGZdYb2zaw0bGz8vhiOmDEGHs14bayDFh4OkspWs
  3914. G"dWepqtjB8aBLu5FYu1l4peomA2T0mSaMj9WcKaDu0gWmVXcSaFu4lOzEKf4aGOy
  3915. G"MtZkZZNQGnft9(O4CLtXAZmfNxiZWsRqMpIEUEfM4A30UGsh0rAtwdGsAanmBrW
  3916. G"5fSf4OwGdMGcuqBuoTVzJMNgyv$Vd6K2dInxXkGewdWK6$vqzKhoeKhag7JHN0e
  3917. G"uq7uwSHPJ4g4y3SSnSNvbhlIu9fu1mE2R35oOhclOZgXXa#$ggWVtj9Zli4Chrc
  3918. G"FIA8#aXWAo2AA#88$C5k#yTV7YDdA22sx7wMmx3argJhXpSciOHQI25TWqzY#b$
  3919. G"OHEin0JGH2kSyeTI3cdubW5OkWPPWmEWoA$1qu7huULDS0npNiJ1XHZMZLnGck3
  3920. G"II7PatBZ$khuUXdUuW2gtBeMMshU14fniTejpxC1nJPfGX0eWyAdymncmMwbgtZ
  3921. G"aJPDW9aWoa3tz8nWyAh2xq7LjJBea0liJmTKfWSjLWaAAgUGegWYC0tsPNscFLe
  3922. G"Elj8xs4XKWNjHlx5bVjHNtcFNeEpj8Fs4bLWhkHxuc$O4R8yKFcwdo382wXqMsR
  3923. G"gbs7FzA1Hcob36cj0ozl7dSUL5InTKfc0xi0hMxi9ygHKXLPeupCi$m1VCK9VSt
  3924. G"O6wwk6NlfMcfa1JLTvW4Mcp21AHRPcA$cjt90VwmKCABZWuP6AiOZXRMooi1YYr
  3925. G"bRaBiUS2bVNTVrUhez12XQUUTTSKWOhTP9SOfLcEaw$DzrXH0omkoI2PXwfkK6x
  3926. G"qb3XrClkppk8MmeGFyZlq86o#2#MRhTbPOl5ZtKZYvisVz8YP2krsMH2sYxa2oY
  3927. G"2IMISLK3aLlNDitP2gYuTTH8kG9EBS4PAwncrvYQCD7zJHYiLHYUD6xNBA1JYS$
  3928. G"nLzcTTMymZIeK$tgJdiCzzdtWq#egMbW$TF1TL9UZ1iSMaXk0z7qcG3d2vj#$kx
  3929. G"tkl#AAmDPbGLa2NlnHyT4TQ1$uWAbvRp6cggBlr1FcOLQnxP$d8oG1qqLVcJTEz
  3930. G"1$Zk3IQKNP1GHWGsypwA9OqRHUGJPk7LjRXfqwtpGSMtGHmul6xxa5zBx0FqxqB
  3931. G"xgosUmKJDmCSiRR4gajJJTKrJEauojmoMeczJzxLSRrqNBaGt1Vdg2PdxC66I9Y
  3932. G"cPCyDliD7BPlikdkiQwbrpxPLrN#pxqiS5QXKo3WGWTKY3nAdekCBmh3tYK6uIw
  3933. G"LrilylzQIPhjiOhBnzRo7w6G0I#S4ws9#mHdI09UVjCOlVIYlNUa1sdqGc,qVtw
  3934. G"XfgV49Idd*m*i*m0tmfJlevKrofutfbYqpXumnOWvj5erpD1qp1eubrvdkqurtn
  3935. G"Kujbfvj9KtGCYqpXumN0GcA0GcqT0aeO*GbaqbNvCHfeOoF#h)C6b)c*d9etX4s
  3936. G"tbbvdceGeJqrf2CdAjQ528uGbsmbrfBVL3FQ0nSJDTGmOSLTVDSHLUP9TUfK9eK
  3937. G"X0MZeN0eKInV0TSZTHki4nih7BzBmqUT#lx6csqe8Z0Y62Zsx0OC3PHTTLb5wWr
  3938. G"COSnSZX$hKWeMWmM6G4hgj$ZCO4ejCx$uMgZVs1IIvQmF4FkrlI8Py$sEhtCctA
  3939. G"iFL7HK8HnMcLiLlcEld5RlAtRktdkvFQu0pCYhEziFhgyT8Rf5CqSOoLi1Nugof
  3940. G"R#uOJMifVds9jnAqIUY#WlZGwuK8DAHo1PWoySUO#6zWoAAuvsNSUMjVjil0IEK
  3941. G"1ru$KMYioHrRHl4m5JmnHzqQkZRLdr#a5yIdKmwSMuJkKTgsYh4eFijFGDrKpaR
  3942. G"RgcYh4eFiiFGZvdb5d8Hcwdysd5ZWAG8qkhcynqs#ioeSgijF4WAaMdbRbOn6cK
  3943. G"KpmLdG2Olqr#6GqjZD6ucvapRV5tktBmFZYqIuIkLSgInDQhj#4lsYFmOKzAFXh
  3944. G"yxZzyiHmudkrIpqRqshJhzH8bN4JinCZyoKHaLsyiJl#WJ1N85cEXhe45cEXhe0
  3945. G"5cEXhzAKia5X#fwoDBBtb7fFGlnIp1wOd6qxY4GI1nA2#tLBApBAGwEu5#26chJ
  3946. G"rX4MhvQpTQqH8ju0EFw5CWQbrfRMUYnVGeUV59LjRQHzHWMtuCyWSbulnabk*y(
  3947. G"uWzfxS63LTMzy)nvc(G*WqpXumUuewf9(smajvyZj4KJA7XuNU9rcgeWe0uU9wE
  3948. G"$MQ1MgWjCStGH9$$VH3wxtcK9bOdOHDh#rD7qas7e28qI7aYeINQOnTZfKWvUV9
  3949. G"SYnSTfKJnSU1TVLUGuU11TGmncprF6ubzBFlzlRlBydvijgAKoTOfuHSfGceGVu
  3950. G"W8uScuGdqV5yFGbWyB5cUJhbjLJLGDWcqXcq3fppbd7b4FujV03iaBWW2YkdDTa
  3951. G"HiaNzbdydbAbj4qFktJr60iqV9HguMY0PuMTQjcgWtEvxm7XTcbOMrOb49$Qw1J
  3952. G"OvOay4lIZd9euMEWehHj2O8pXw1$le60DGP3cy7ob7j8c3b2obvBa1Sqlycs2fO
  3953. G"JnihjOjnUbbRaLPjpUbc8JW1TR$eE#b#QLGgenvVMzFcXG5odmFpyUswbsLI9Yy
  3954. G"Em9LfaFVz#EqUrnL2s9OvkAvoarlzUx119GOaUFaDpU0Uh8K7EsXCVECJQpLkI3
  3955. G"EeR4tlF6uC$Fr$G9R#rkFuY3qasCVApN3Er9heGP$8$tSheITK#eHRVtCTf7fx7
  3956. G"6naCTLnXN9bPy$Haeef7qOyEekMlHI5tOyofkMxHI5wOy#fkMJHITR0AqZ0sl0i
  3957. G"rSBT7SCgj2odK7hLDTKbaDt$o6gAHq3a#efevKweITIuagg$#sfN9KW3AnfaFZY
  3958.  
  3959. G"MBL1Ry$kf7d2e6M7VIgTewFKu06fdqrd#tv047POHoafnxafnqTYcOObFRkA8Gv
  3960. G"0qpGIMNGIgOoDbye5Zc31q93U2RFpb9ttI#vTkWHCnPv34ghqUJDnx0BzQA75Qa
  3961. G"kZAxfWZL17vbK1inqwVwqC1y8UZGQXkA0aPOvO4mb5lfYf$#Q53iv7a8BGUM8BG
  3962. G"Ab8BGkS8BG9x#nKpPpRE9RjFzx6GL$JcW6e7r8dWKMOe3d4Ufyaz8hhm59FIplb
  3963. G"X1tpumEfEFOvSBaHtuFtYFac1ftClcvn1lqXQHb$O1zaXnpdOhEMgDobhQgCDo1
  3964. G"y$a31Aw3emLe8$2mom128nd7TzyFnd7Pzrl03ft1oe90hG460CBK7U$2DUao7do
  3965. G"ad$sG7m6w#$BHPFx3MpdwtZQo3$$VMeW9eG1nGhXyLUY03wmGlo6lE5Z30lw50f
  3966. G"HZe4Y31098RVd36FWfF$p#7GgWytqwZYGkNqbdEjDSWYFHR617El#XH1vrLhGsD
  3967. G"XuhWNs8Vfq2NsqElkL5IVqGJ16cXydKH801G8uG11GXgHi8rI$sZR11IwpuqFUd
  3968. G"vD7uc6qPAXP8MPX6IDOdj44t5ITHvDXonNGmw7ZC728$EKHeCUfySpDrQBdQNcu
  3969. G"77YkBvltVVXib$LWJ#kdaKjzmaxwGOpZKVEnySNRc9xVeo2T6vZ1C81JGKPdyaJ
  3970. G"QctEDLOVPzb$LWJEUGptwA0XWDFZbK5kbz8GOgNLg8OeWVMUreRkK8qTUlWvjkL
  3971. G"RBb#vstyhH80BAVUnGKvmXve0XfO$Qx76Y8l#busMxPdFN3FUoCWVNGlUGlSOcK
  3972. G"UY$$Din9W#eiH#wsOjt3N8X$PtG$EGtoQahDTSFXLtOhx8F6HQ$ZQw0sVsSlhpb
  3973. G"7rbhGY4lE8snQlt4dTFdiqcQUtNEyu7TlwERot7Nlq#ltYZFwltWl#9dy6xv6#a
  3974. G"I#o$pQso#WkGJDVU8hBqdhGHhXbmu6U7ypqfFXW3jgHbmFC7R79TzIT5CdOnzSh
  3975. G"U93Y2JOQydANWbCMs$x2pRfQcbED1pR5jiP7#5zcP79yE6o2J6eNv25SJoNDQYt
  3976. G"rsxsYtUCWDHUE0XgpiANYRpPDcoWOV#RV4Gh90pXOJ6awxNV#aqFS7NiBxyStdp
  3977. G"2b$3yhT1x$NA8pX#G35bE9Jg9Zf8l#4du4aLK#h9qpGZ1G4IM2P3N9FuC2NylqA
  3978. G"$IAOo#DSWnzI$Pjz8reIpmUy0LLLvwRQ5sx$a6sRk8c26KoIGmhCx7C7AxlbLFc
  3979. G"QsvvqgAdcBUoVOVAfNv1XL3dBrW8jJiZvb3#VENIidZ70D7Dsp9UgTGYCf8byf6
  3980. G"hZUR4QYPgsi0fdDWShHE41uzubJzSx9x51h63SDZ$Vj1zbm6in3OUQVIoNC2n6I
  3981. G"9F0nxWJERdq5EHwgJprRno6AuxUmC0VXpBR6fDJ5GsPY403s#V4NTKAO$lzg#ht
  3982. G"64R5IwK3O#3K7aNxlXDyuoT$xhFUCDE#NIY5SC94NUl0XEvFiPosukp$yt0IFzv
  3983. G"Rpmr0k$bCxfaGwCCJlWh7og4l2Qg0xeQ36DkC6crGAz6YWl5wPwwz1G2RF9wAQZ
  3984. G"Dx5c4D9k2YPXE0x8$vA5FuYlwFLtE$ONebnRWYNQhODsrMCRFHEQ6vd8ymbpSdv
  3985. G"$aJI2dzm#4cUfqNwow1xiYiCo$hSRdB1ylKJZm4pglydnycpidridtidv4bxGXB
  3986. G"XgAXh8G7ggrjkrbWX#G2WHkqP2WP2WR2WSUq22aomdxok3eSNhWkmWkuWjKWnK0
  3987. G"l05c86l4a7i0IJUh2j3gGM#$Z0ywrNIBkJLTVBcMWCTJjeDFJUuNhKUwCOdv83N
  3988. G"NtuUeKNK0UkCO8Kxi7k3UbCOUuXhnGyEuc9dBWNuZaMIkpbgezmYVsGN51NrirX
  3989. G"3c4BuIBhp#UceocYUb1S#zO5tqzlV6sm6HY2qZ5ekFeSnXtpbKJVyJ8lyZYWfJ8
  3990. G"f8kEyejqbrEdUiO#fk96#XE0wtxnWi8bIC5srOoLpXro6vZG#ixRBfRRm4dwBDY
  3991. G"ZZbV$aE3c0ehWR7W6LF$ShfXnr#g48VeoFNpxUyCGzFUmKXbpWblP3XbtN$RNeO
  3992. G"Tw3rVE(38jUyNY$vImdJmE$VrLzl47rwjy2tnde9zGfzI0#FZhnLnElcjNU52NO
  3993. G"kKbckBVjethkLOKB9XLdTKlRAhbvtBZftezj9L7m42r#d2tDu4K2GtriVa$pnm9
  3994. G"gYqGJDj#Nf#YrEkk$bI9asaI6fSiCHN#bDwvulxOu0iNW9UhTs8lQows8wuFDbt
  3995. G"MspDEv12h8vkmRMO1Dft0fOk7CEbHmSYDTWMuAW1r7CDDrx$6j13BsfFGKMrU3M
  3996. G"usUbi3gxP4qtcFzuT5igF5PxV$hWmvHGOoV$KtvNTtFcrkJBmzZYr$xIyyCXXFJ
  3997. G"gdBrO8hOUMRzl$WsNGvg2$RVN5xPxOb2grV#oT1LdPft2G$iiSwHOwW0LSO6w4G
  3998. G"94eHcctvUfJrneP7uxmtAzmdy1NHcKKVhrINS#b#DDXd8XmJ9YzfZfWZi9srnbR
  3999. G"lgusEDfAG93xhOwfpPwEtA$dPZEGKAgghZY8g5W9RoLR8Fwb8zlLJAemB7iRRVm
  4000. G"1MBv0tgl41Tefv6SWOn3PIQZkxOjMIlUQcuPjMkHCVKrnkfPwYz1b0UxaAnReNp
  4001. G"7vY6Bsexb8W11wyrJItZmY4EBzw6XNlBJ0ChkR7UebRBwxU3R$zTCKyngzEcq4z
  4002. G"j66QxywxS3d86qY#WqYX7eAoNYraHKC6Tdu2jGY2zvpZB0Jzdv1ED5ovAPmrnqv
  4003. G"I7L6iocOHPD7vGDWXCpVZg7r6DrildlDzklJiDsn103CaUs7BS3WbqG5#7Odg#v
  4004. G"q6kG$H5VLmM5qz6wL650b5Pr9#kPlhz5nyCkDJRF9uhY#k3j8nJ6IL8jiH#0hY3
  4005. G"3yu11v8dIu7bBE$HT5BDSIEa44n0dSZ8a51xQL5eBz76ZmUSJTPRwr3GKHvK3mG
  4006. G"W2Q9TEV7JoSJg54gursC3VqixyDwEb5ZILJp908hXfjYFVIphyS66exKZCe0Q4Y
  4007. G"#cqCV5lI7PFE$cEVJ0Ej1dAcUB4oavFEc3nDhqRphlvEiQn5iXXth6Ioi#vfGUb
  4008. G"pe9jBikirxafrH4k7io0OlqJxWiWZWYuEkybYq3WTULNGFWefC7$6rgGF8bFy3n
  4009. G"PbkB4laMZTaWHD6shcbd9diUcymVE6kH7hXfijlW9eva7TsueC0e3HfWD4v#pE7
  4010. G"r4cU9UUiOoNT1WXV$lCT5BBR1KCa4e8FA$GvzFd#8O86y7qZ3czUVII2edPe3VH
  4011. G"ekpo0kMPluLTpQAw6wSSpi11ZX2rxnzR$6m2LAPvSz46v#y$jcxkk6diax2rH7R
  4012. G"VoL6ef5fmH69T7FWgNH50MSDGY1cdrFW0nEs51SSDyvDWu2#Y$9JU#WLLnQyF6F
  4013. G"SAz1FrnxyeXHS7Fy#F4dH4qH4BH4DHiOHO0HqHano#OD0Ap5ufPi9DeB09tmvPn
  4014. G"jRteXP8#7JUBaKUqs3NFDh$PVwk#J3bYsqYtSKj8RtYheloSbyShGl6fq8FD$hC
  4015. G"PJU8DmDZ8OpEx#$tB4hQivbPB4O3gishlRwHNWBpH3D318hKaejip9x$MA92$8S
  4016. G"fN8gqEsj#oMNRizgG9ecHY19aj7cm959$8CekZbC6D7$m2ry6p7$v0RWbC#vzDF
  4017. G"ahMhqw88EX7JT#5pi8HPmB3xT93Tcb49h$adMA7PFN$tTJe#wO9mMhNHOhfZRuq
  4018. G"r1Ghn9Ghn9txaNGkLngfhIRxK80ijZKvhJ80jjR9B6DipzsYm4EcuS5uJD$fVs2
  4019. G"6SAnLdiptJXEJm#6ySvB1xkJ9ez84Xy7d788ng7IY4htlN55CYi6ULUrLNWLUGL
  4020. G"NfbWBEEeiRt$UkRRfAAflWg77h7FlEqv$e7KN#4hajEDQMo2LiJb2IaRgIp4VJw
  4021. G"H$o8ASxgVWS3P07a5YGhwBuWpnRRm$h#5PFyTVyfWxWxT98IDA3jEFv$593YomK
  4022. G"5n6LrL15OieG1gT$ySUWas7$FWCncqL9srMxU9x2$#Q1D0dBbeTX8s2$yz6Ewb1
  4023. G"O5gEY#xN5cHy75EhL7QKCNhi3R4uln9njcYG8Bm5aXi5mee5#dVtVIJ$3juLlpA
  4024. G"FeF9kSNNzcoo9dG7mr1DNWtFRAblsoeQvTNYjiDMJ7HwYpyJ6amMbAThz$as2ie
  4025. G"AABY#5IiMwRBcC3YaRu26G9$zuH67LTrnj8OwUQSGWgCVGh5j4bWJOFLhNQsnLi
  4026. G"Fna0kbiV#46RHrwOdvSFITMhbQA4LyLZlFyk7OkaF5rSvNN52NVXnBZxfWZocwI
  4027. G"S$07ljhN1ThanBvMpajYvWzPPm$b0Q33fy3YGZdwAeURn3s77bAZmpp3S8$EiwV
  4028. G"qT5Nv4r4KdNxxALHZ6t21csJEGgG9Snd9oC8gGVCy0z#t0a8ccZGUUWMogBBgSS
  4029. G"TYBH#2s7GWAdA6van9dG26$eaTdcOz222gJxrY3NSAGvZ#O0T5i2H4ix2GeDxUD
  4030. G"c6hyVxEVEdF0hjkikBdM9nOyNaFZHj63maZ6xpWN62rBgti6Pn0UBqa0V#o0KT6
  4031. G"xFhomK5lgAdVKAwm3IzpcrF6yjTWQP$Wrp2WvgFCo#aIq9W#CE4yIVtJGBY$$uc
  4032. G"IxiAYfHbBXXnPJOyVQGeABFuLsdZoP6f$Eg0CTMftQEDrNgSp#neJQcOgF0Qzc$
  4033. G"Sg9aZe14leBW2$v6iNC8b#dF8zyBAflC0tQTbB$V6Kme8Fv4c3MJrh4Sp71OKOc
  4034. G"F$4pjHxYhE6eeM8mN2jevQ#R6flCNUEST49Zpk$hMmbyiezqkU$8iBzsjiIBcbr
  4035. G"TUXZxKBmLRJJsueGWNnX3Go#U$CzWiSXij2LCnngc7nWai$JbqEH6A1QCqD3qOU
  4036. G"EPxy7lM5tbcnggIJsi8mzqUqOPdpGpLoV7FKEGfl9DOI9Jp1MTdPMbbaWG2Vnqy
  4037. G"ysfqUYEPqSJVtdxkAO3j8kh4aOGYt1p89hhWkhch3G$QG4m8wemxb7B0cFREAOu
  4038. G"udfjyPC7eugb4ySWCHFa8JxYbOa$hRBefyCl2t3KywS9ch#6kXQl71DeS9$1Zp9
  4039. G"mQX193jujL9gGoTUXaw2xp5c8kX9g7v6pfI7pg27Cce0cnHGkZf8kQbKrhXnG$d
  4040. G"AFdUn2UMWXgWi2PYlsB6ZJDEFasNPpqtFHbGiB3ak7iC97PwPr#tFfMC6wVe9vW
  4041. G"D7Rvk0g2lXgikATRpT#7tbUIZWEoiQYtplNhF7h5izI2dff2IFtbKPUG5CSdHRs
  4042. G"a7x7RHlTLcFE#j86tBCJlL0ScfPMEKwyAUS#nNEMmhP1ffGrmL2EsC0wHVRPgFE
  4043.  
  4044. G"DW9aozHQMfHsMdsfuKR4OJLAp2r8JSdrh0qJdw9H#id2CEuzMlCRgACgy4HJadp
  4045. G"6ZkpnC0sGaXjBlFqdAuu7Phk4UDokdBju9#G4U#WbDfwCRIWzC4qYpngbc2lw#j
  4046. G"2S4t13h$pHTc2e4s1dbG4AMVyeHpSNOgG2LPFaGUVyURRz$7jkf4CEdzi9kf$IP
  4047. G"g9bQx8wmGRam935#84TQfNN6OiX$pdqy5SnwJEocqvT0$VtBx8Od0pi6nqpP2tp
  4048. G"Mmbp2umgJx3PcN7rd4b8pZh9JpKrHiBrGiRfD1rGSJrN8iuDpYvB$oZUCoaSnym
  4049. G"3#HzuPtnjSAD5HzWXypYHl8UvWga4zR1DD1216UU6yC#xVjmBZKeTdsox8MSZ$G
  4050. G"m0huDiM4MCUV3apWkjMMBUOIXaADrn9VmEkzBgAR5uGy37HUK9uiv9fEQev$dYT
  4051. G"Fb5gwMj36XKBF9cBHH9w#TQBk5ETBc5wY02uXnF9JcWWdTGd4oj#Cp4kjgSWS6x
  4052. G"g1E#vFQXOnVWjcMP8gOaShFbOFM0JAVOPZ8X7o5MY5h93nTEm0E7MU9I8Fd5mUy
  4053. G"BA#bwCpc#bGskaUFTj1N7kqXCX$kd3P1R77X6h9iXTb2DlxTFGp3hW1VJaGoBtF
  4054. G"G$pd1Wq6Fr8RttQLdORMFvS$Gg8xGp6bNRxcH7la$)l#bMiP2M5$hKQZeoCIHyv
  4055. G"IpW9N4$sWN#0wi7DJVlfpEb80Z5van5jiJydBmToEXB8Fni$x9Qp6rozyg$Q#eD
  4056. G"tidbDcnjJ7QanzI746PWHWjguOMNl9cpXCbe4pQet0kHpa3wfHtCxS27I3D8eC4
  4057. G"bfWH3$tPiKeCV4VGOhf5h5Ih#wrffK2pKFhWWFfH70BJW9sS2ziKBmvc8E6Zn8d
  4058. G"e#YDKTAechEvOgjjq9ChXZwiqdTOfW0cVac61iiwP93QMd8TU4JCl9rrWP$zCRj
  4059. G"ckMk3hy#a5wFDbQygYDKhbczHN$r9Q2lgANUMf936#QeNaeTpaoqojSwT3jc02N
  4060. G"UpDGoFUjOlVUH$$h$mxVqXTGrGiVnzOv$a7jaQm3ccwdiU4Y1Grx91bYDroitMl
  4061. G"3ogTeRfossQmi8Cey73x6Ju4sHbIbOwNBd4E4fZFC1tTE7uQw5n0x5vCHLfu#Dv
  4062. G"qk4trHoq5FCcKfnM$RzDyDNtzcS$Hk5VDNa5VClyoVQ$Nlgfku9GKk#de7cNtG8
  4063. G"l7W7dy#h#vWt#o4Vl7CtER7bshMWqYrdsuPxV8WdPK#ls9rFWc$Kaw8WhQlM4sb
  4064. G"titPzd2EDPWbSbhmpG6PJQh9p0Fq0dQPsC0fFTc4s3E7qdSZySnNJ#8KmfTVF0j
  4065. G"2dWzGOXKlqsN0ON#5x6jM85t6fpVgJ$iJf2bx6RbUXo6KeYB9fYJsWEh6Hm1hps
  4066. G"GAlOfIqONx6vk8nU9roS4Wl2AlJeOrkmewJh5XJHGq6c7VVGBvHogBcynhig4fe
  4067. G"2BOPE9#I0meGCemB8h8AtjpajCaLGJYaCYymalBhp03OaoMNtnoGJ9bgWBfbXaS
  4068. G"ah7h1chFIo21X5UII#aU7nC8i6zhah7I4yV2A44nXXUgyHDagJJD$9URJJ9xxHJ
  4069. G"Fhh7I5zNih7g6z3ih7w6zFjh7i7zVjh767Eplh7k4yNlwLmmG$VGbCq20PcsPwx
  4070. G"32sQM22wwqY00kw5gw5Mxq2sqo03c38k30Ew0sxqIYXMsqgZCMtyCc2nnTJvUVD
  4071. G"UV1mtx3lx4Sq97kgEbxgbO2LJ9TSfGdnSUfKU9nzN9xgKRAfKMnTSTSaKQOnTZf
  4072. G"ec70nT0P5Ko7hKWnSNb5FRB0gisx0k3YW9KmPoLOvfGbjylzQIPhjiOhtUVnU1U
  4073. G"LoiTOplU1062Zeois37#MWHQotM0cuSwGMeO$6q$Qrtktl6xE7n6taLBWUsnjyG
  4074. G"rJ8boWbQAqRqfemi5pWC1f8a9anJRvas5auSsscgGXHxamdVafWSlGV4aOPiJMa
  4075. G"UQHRaoCrAaHfGKLW#bC8guGqKGfTOfTGfiyVMWycvGRGeKWeQy9aZegMWeMxfQh
  4076. G"4z5EocblycwyAhU4fpbpcc3bq3JqeySjCeRO0T1LTSnLgyVbZVahKc0apcA4Dhc
  4077. G"KBq5nSBVHD9nS7$bSeyYUWeSlZhS5OCKGEKGGKGIKG8KNobu7J6tFC9s1gqL3qf
  4078. G"OP1H5HDSRj3C7ww5Aw2#27eDHTTToJTLqZonJqVwZjBATBAjJMXIrrn5TUYaxXb
  4079. G"4YOMyz8BRtMAhDV6pMEdkz1pBDyn05SUNG155yDGa0L1vOSBCxA35pai20Ilhaz
  4080. G"NoaYIE32nECUgrRYGOLXYddUU2s4#gUYq6RJFQWNoBnlBBSMmaTha35XyUzdrhe
  4081. G"QZkYEyN7CeKsTXOs#aWAxGeaKfTJdailA3oaqwka1sdqGc*gaGMCwXf8XkPxjrb
  4082. G"(GQr)g*m0tmfJld1GabiXiuuHn3GwIAUnpfyGetquX2B59hzAD7yzBDjBzbjpNl
  4083. G"DjBAFRlrRpBOcMo5yPBEHBzMo8WvUVDSLDUZP6W1$wolVpd1ruKSnS59T1LouVf
  4084. G"b1Xo23YMOBbpQ$RZ4Aqi9J2YgwYccIN7O6yPBAPlBKFvC76itwXkxqm8nDKNByz
  4085. G"BBbbXJQJKW72y8n9i49lvjibPtFkvlQomEpeP3WnnA7M9niRzAyL7zsE323W1nB
  4086. G"b5ldkt4EdYqgYqq8wLVyS1Tnm6DJYuC8EpcV0#bPrtktlY2lR6MnnuTn9CSOry1
  4087. G"0BXwxZA2YkhPlMF5Von1ZAUBwuIc5l7H8kPubTwK0zivz5cSVizPiVRyfzktji7
  4088. G"zpbjmm3tW5EcHdtATViFp0W6wq623KSs#jiIFccHfTVW2tyzXJvUrzmuU3NYP#Q
  4089. G"p3Yi#cUdK30TUYDmdF95jeoipPmpjiwwtgMTLvLD3s2e#A6LAUQ7UTZ5SS#h8P0
  4090. G"LMTT01odvT0f8ZDCDCtRXJA3H56hgvxA27i2fu3O0eDpz5CtRElJ1Au0eqmLSmM
  4091. G"SyUKPajtj2IOGpxDCLxuhnxH9ETPfolxn#DSIXPDZwtvD3LYTmpowxNuPRzzxd3
  4092. G"WEgRNOSUUrP7ZOvnzIIEkwB2v$Xc38Ic1RkUnNAQI20eVs47DkdFmmBEvxsjwyI
  4093. G"VASGM1nYcAVnauz82amPlAixf3aGrfLLzZV1xjrk$eU8iEYOgBYgw6ggVdh3fRR
  4094. G"LZM7WwPSommvDEO41wDFuMgc3KfRwkHm0uFNstCPhPvfP2G4VHw2Fk0#x5kmTcx
  4095. G"tbZRNL4fMWq0LQ8lpHLONG3flCa71zD60KY5M32kgQvgwho5RfdLtN2XK8MT5HT
  4096. G"PsDcWRM8R6uArX4IURYInjtQtjAveIl#rz04mRtJXKg4vpVBBDE#fBzqhPEARbT
  4097. G"mHjmbPtgeTthM4Sj8l2WoNLnJT#xO55OTIx2$ZfndPMo8hUZXYBCMLWip33Kjqt
  4098. G"1fI6ch7zTz5xCZ8G4MlRhfZ4FTf76u7Bqk1Nofk1726auLqWM2#sr3WohPgUzv1
  4099. G"YQyNq#XsxB86XuErteVyKuB3UgAVXhIBFnwZ3xaoDBACA6OxgxxNnss5x2VoMtH
  4100. G"dTtqezYYoTytlzWo0YtfuQasDmUoylJRdnkX#mk5kPlXbPSNYrO21HrtyDXPOo0
  4101. G"yC$Acg4n2q46XFxVhkeBA5YG3UE3YymytjQZa$a1HcOvulcg2bnDV7BwSbXb5Wg
  4102. G"fXc5WgvHc5WMcix7u61yyJ#pdBasSjk#UKIDycOD0G4maFBNf2QqHnEPZJaqYKd
  4103. G"mfCafrotZrXr2gpnkb5ztRDQZBMLH9klvQykVGmf$hhpUqNh2WOZdCowxMvBkOV
  4104. G"D396xvpULZPKOLWQVJHfHPHGB2PbM5Hpmp0KWG3WyUhJ$teEtAd8ulp#o83DTZ5
  4105. G"GLltykJeweKrw4JYiuQE0QcEgz0uOZIPKHCmuYKYqjd#YqjtpdLmQNNHsgyNJkp
  4106. G"jmwYOvi0eHDdeknMUaKspLnKB0uhMcyozkiMH1mAIjD44sPBItkRMWRAY9ibXlA
  4107. G"gXeeeS2feqfOGErmgjc$eJyhYUc765y8QOeB8H0i3zJoKJCkG1jOSnpidjE1qnT
  4108. G"#TjBvMArX2457VjEd7LvADzfdKrxIXTO2Gmb1gqb8MxutJVBlpRH3rIlcca$2Iq
  4109. G"H6ZhbKKVyplilemecoTjGHjTOnHA3A0MOTrBcvibNfcWbqT0aeO*q(WrwECb24#
  4110. G"#Fid)yp)Gc*svuqe1urUq0tdrf0KM5acYmW1aIX8g3qNWKg3qq6GMYaItmKtaIj
  4111. G"ggYug5acZKg2ugcAM34rjsXPKMZ4MWWgqidxidqeg3qgAkM3yhkQq2iYXqN0SWg
  4112. G"OaqkYpAY2eg64cqaIKqhAYM58MeUWg#qcggqmNW0g4Cu4iN3Cg54vqiXLMq5uML
  4113. G"osAAvFwgGku38XqwgIEN0irUMN2KZPYcR2M2uggQvBcc4eMZqXGshrohxquIsLQ
  4114. G"Y2nwWLUvZm22G2jExro45ugkoK3WgxqK3mgkR(qTuacS(k*y(e7yfxejXa4wah)
  4115. G"Gqb(C/ab(i/m0tm5crpneulfGalaGc*gaGJtwXft1cLniCb(q$r)f/q)c)Gjh)d
  4116. G"9etUGeulfGalaGc*gaGDfTceMMfp3by)qPc)i/q)c)Wcn)mfuwpvfvUGeulfGal
  4117. G"aGc*baq5twXf5gTkmoi*T*e/q)c)qSo)d9etXa1sbiWcaO*GbaebNvCHHyu5vDO
  4118. G"*Fe)c/)G*y1d(WqpXumU8Kqkb1sbiWcaO-07KvCHXlEV4W+d*c/e(G*Kzg(WqpX
  4119. G"umUqurgb1sbiWcaO*GbaqbNvCHfeOoF#h)C6b)c/e(G*8Eg(WqpXumU0uqqb1sb
  4120. G"iWcaO*GbaqbNvCXQFx2AMHb(0uj)c/)G*mbh(WqpXumUuewfb1sbiWcaO*GbaOj
  4121. G"NvCbFSs6vsu)OAe(Gb/e(G*8jn(WqpXumUmeulfGalaGc*b(hz5XfyJ77$Hm)G9
  4122. G"*k/q)c)q15)svuqe1urUq0tdb1sfy,kaGcaqH)qX6+a"
  4123. N=15599:K=255:IF LEN(C$)<>20799 THEN ?"Bad script!":END
  4124. FOR A=1 TO N:LOCATE 1:?STRING$(50/N*A,177):IF L=0 THEN GOSUB G:L=6
  4125. W=T\P(6-L):GOSUB G:W=W OR T*P(L):L=L-2:B$=CHR$(W AND K):PUT 1,,B$:NEXT
  4126. ?:IF C=108 THEN ?"Ok":END ELSE ?"Bad checksum!":END
  4127. G:I=I+1:T=INSTR(T$,MID$(C$,I,1))-1:C=(C+T)*2:C=C\256+(C AND 255):RETURN
  4128. SUB G(A$):SHARED C$:FOR Q=2 TO 9:DO:S=INSTR(A$,CHR$(Q+38))
  4129. IF S THEN A$=LEFT$(A$,S-1)+STRING$(Q,97)+MID$(A$,S+1)
  4130. LOOP WHILE S:NEXT:C$=C$+A$:END SUB
  4131.  
  4132. '
  4133.  
  4134. Msg #:  875                       QUIKBAS Subboard
  4135.  From:  KEITH WATKINS             Sent: 04-08-93 11:39
  4136.    To:  ARTHUR SHIPKOWSKI         Rcvd: -NO-
  4137.    Re:  C TO BASIC
  4138.  
  4139. CLS:?STRING$(50,178):DEFINT A-Z 'Created by PostIt! 6.0
  4140. FOR A=0 TO 6:P(A)=2^A:NEXT:OPEN "B",1,"CSTUFF.ZIP
  4141. T$="abcdefghijklmnopqrstuvwxyz":T$=T$+UCASE$(T$)+"0123456789#$
  4142. G"qT0aeO*GbaqSJvCrKedGBbC*cf(Wb*d9etUq0td1GabiXiuuHn3GwIAUnpfyGet
  4143. G"quX2B59fAzz7BVlidRClliPlAg#V7Bb5CPRCR7yPBDIEpxq62YwwYe8Q6f17Zww
  4144. G"6csYgw6gwqAw5#22cYPM2Z62WYwqo23Yw2wg13P9TUX6DAsEpxx2qfsfITL3Yzy
  4145. G"LXibzANZ2S2JR5DyUwlh6B6RDlz8UBhO11P49Bnt172sx7W9szDBRtXUya$bPmM
  4146. G"E$w5qExSP5ETCZJZZ2W0L7wWtPWSX9D1DDplAiVdL9HNU5foh1rjCddqv$Dxg41
  4147. G"UnnaDo3uypNkOhgM1OKkGVzJ6HVUUb5fB1ePAq751sxen7UmWAlP6#9zbPCK699
  4148. G"JgPUzlzeQKmhRmY3nhP91XXimNxgXherFoJ5KSIvotZxYEQHZ8piBBAaZMB1G8o
  4149. G"7VDtss2w4ONNuUhJ1R2vj9dtu7SW9f57YSNR5UmsDDPZBwNx6wgLvVVeQrncG4a
  4150. G"7aTdTs7MRUB7BC6j8k9TCjtxjsId5XD9YINGqDwS9wD2Xqib5Ebjic#FPkIcSGj
  4151. G"rHGx1CX7A2MNIuRYx0$A9tUVCedYDWFdyYEcYtkZtCgmo3dYy6I5ql0ycYwWCxM
  4152. G"Ueg4bezbZybh8yMgimdtYkJCJx60Fji6pqDk9xM32kM0QbjB#RXFQ#ZCcJ4v0B8
  4153. G"89oS7a6DF3XxgMJW8YIPf7wUycdfzIZcXpG1HnnRXdNc35MS9ljJ5n3mg5pLy8M
  4154. G"PgBnrpb5rY$fB7BnMZSRSWPq66QNYq2lBAYtR32vPlh6tzcUHgewfrWvO$FrYvP
  4155. G"Lri0JdibgldAov#f73KHziTSzw21JKbIwgew8nzUAywgXrAFFGLn9Enlde5BmcJ
  4156. G"EUXqziTSqXQ0D0L1T0z8IOD6KgA4SmGPmzH0Xb72Nri1Ynm2f0UEvBObb3TYU89
  4157. G"L7MDbCww8iCQn0wgvOtSSjKaYVfUJLnidHLPUE1P#xqKQeLEojBiVkEtNePtgyb
  4158. G"kCp1YqGxRh7AwgeRlC0Udcz3Pl331nmxHm4gliKfGzSqkl8Xql1YXkgHH4ndS6d
  4159. G"duLyzGuPhklZg1P275lfldHM5UToyMvsnuPy8LRGhw7SYwLjwsdPMrLLQyX9g8V
  4160. G"S#slvSESWrPB7#f9KvDS2X2OexfDKrJJCJMNJXM$CoM$C4CCA1CoMWq#fPAthgD
  4161. G"L1u10XkNZUJb5rc6BZoshcevNw9WzBXdbRdbvBd7#oS#GYu3kkKvCsDEkCHwyYS
  4162. G"LYYSfGZ9DBYLwrgjP35XNxl3DunbBSNJh1L7edYfNjToL5oQgrBQEJ1GFgo3m3S
  4163. G"cIxD075QJfxOGmmGXazqb7fIWXXT6i3VrxTQMGYbciJAmusHTDbYqk4dzDmG2E6
  4164. G"A26Oa#nz2ADkIAqrXhidSLHwALMnBazKOOS4PazGMqoqgJ7ql1KI7qq3II7qdTk
  4165. G"wxw#bhwvZAGXVRXDqSm4ov9GXTxP7IAWPT32bnqhR7r1Kjy78eezulXobLLmgOP
  4166. G"obKPtvPw1I2JRhIK2gMvsHBwZ2c50Yzs1nQ0x2yYe0$DDedZiX#TFb59DNJ2vd0
  4167. G"icE70Ns1Ia50z5wTMjugHc2xw0B30JxCZk8WGnn7QDEk$rJU6U5wS4QdLgo8yhl
  4168. G"Mybzm3XWYXilxYVxBAHte#Co#4W9W7ZjcR6hNsC1ifviY4Q#zofE3SJWq#AMADX
  4169. G"7Jf2fRD$Mx71zeWRGI1075G#GCkPPDdmPqD0UmbLiRe5YvkzXooZzkAK4UAmayf
  4170. G"ByvlljcmkSSq6ragf3vltmFeZJemgVDOVMkVp07Oeg18mhmieNJfK7LyzPGBqNM
  4171. G"orWh7r4eVLwf6wrxz8Hd0FyGJ9nnOyfPfnOePXdT8B2p65$TqEzx6geyl7a3ipM
  4172. G"qVEe2WRehL98ykdFQmjSDAu8DB64IhnSi0ZbhrGaBWaTriu5ILeUKPVWeJdCHsf
  4173. G"AfduWjwGd5ZD0KPZjokplob$yUx1Jg3TTUOUPXmoTNRTD4wt2fGDv54Z1fEwWWw
  4174. G"1e8de6mmmqanP3SPZUDb8kpWneF0AO0E6c9cbWGTIu52R5kkDHbsGkvOYk7Juug
  4175. G"qAXv5$CR3uMDDh5SnOmIu5ZYgbKDvvY72uOJBSGt9bJLD$#Kb5aT#eVfcaRBtgS
  4176. G"4nBDcv30uAWcmmVAkdAqzDqpbecGhorWzagy3HoSaAndoEHuutNWWKNcqAeMSdn
  4177. G"WYCMJeWbd6xnsvLoo4ZJjo#zdflHpH3DTZ5JpuOE04bR5h#8TjEaSYuqOb$IXhA
  4178. G"yPo70PmvOb5itbJZgyMjmb30MqO8xvtElVtaWWrDr0P6#QFr9Chhjm5yvwpoDkd
  4179. G"b9otycoT82wgP7NX2nSPwk0RtJpMwIeRnlAJLAK#CR4SlanC90ISlm0ObrcqWoh
  4180. G"yhCrGO$YRdAbKDOdJSdG2RdO1ceG0Rd6xuI0qT0aeO*Gba44KvCXuTqzdcx)0Fe
  4181. G"(qb*d9etUGudceGeJqrf2CdAjQ528uGbsmbrfBVL3$LQeKGCOpLPUejgVcUMSLD
  4182. G"UJvUPvmfVbPytRBdRCZlih7BzlBl7yPBAFRBbPzttYlI3VvUTnS0fKXy9VHki4n
  4183. G"iZ5lNjmFjoVjiB6vg2nAAL7C2EB3Yu869Z7PkFrXZruTA$TB2Ft0N60Ns1Qo1Im
  4184. G"9i4v6B5whSvGlrBzdlzb5E#Nb1R5rWAqkN6vQRSEJsZmnR5IQ1SnVPeevlw$hlA
  4185. G"a76P72sN39D83mGL9eKNuMNaTtqo10EM0UDPmbPqC7Ufm3LPlHbwXqknlygl4Gh
  4186. G"Z0aHzyswt3YIx6yKz9hOoL#lZBBftA1GKTPDo8NO$mOUy#IEJNV3HDhqV77o#Y6
  4187. G"rMwZcc8SQip9mpf3zSWPoVKmHy#0nVWTmkzk$PHI$0WnSNTmntNMLGLpzDDtASp
  4188. G"d4IGzKp3b#Dy8MFoXr5zXt49qyB919kZwoYY6wYu2LtagW10b1$9m0IMR#Jc9is
  4189. G"Wn4sf4wzFKABajUB#336nLzx3bQJnLyKnjzfRCKDfbljJtSddMVd7CIhNfIFuXo
  4190. G"mT5EoM7YLofVFRzkYCYyE7Oa6e9eKhj$xaEFRXCMDLfIEKUUAUmK9YMMg7dYW6M
  4191. G"56UaZyZM#CbHQNi4k0$ViViz4wM5MfApOCaJLbnNk$I9BYWmKw2ml76rYarldcF
  4192. G"MnzUAywgXrAFFGLn9Enlde5MQPyx35gdLH0YY2#ghnDzOT24vr70P3QHZYaMYKf
  4193. G"shhHEFgHul3Wyxq76LB8UH1AC3k7sYOC3SlGZYIOUNJAdTLrvRhlBcjG8BH7yzd
  4194. G"YqyzQRxWvD8Ii1SXVQKnKxfVPtO9sEBw5#22G7jwgcew9yxZYGyDHJ2Dqi7EY#2
  4195. G"76gMRqgCJfeYcWmwiLf#yRRCLJvmcdXBgy1hgTqILbsLEOcckEQBjXE$3CP10zz
  4196. G"i0m3T1bZSsQTSn#r675gw74MpDFJC1PrAi1mQSuPVgeVb$lRV0sfRhlCu62UFrp
  4197. G"zvhRDSnkXvrhz04P0O55yIFFhNJ5phohNwnNJjmKFrQ20HrxznvnDSY5S7yqEKG
  4198. G"#2SJ0Har1PvpC2w8qW6qq12WUVtqmZKDRqHSItQZtHl0ctMTuwMTaCUVBtU0kYi
  4199. G"j9opsmA5UJQjieqBMb5IZKwNYChvJOnvVXAWpdNBgG0oFv##SZvhlUqbzyaJbYG
  4200. G"c2leHJJFdYZ#gD1QAckhiGmQXqjf22fidPG$EitjE6nBDua$MmBTofrnOO4dKb2
  4201. G"YqlTsZAsRCDpkklEkqgOjKdKX4o0snP4oe0TO4o0qRI1LLFWHv1Sgy87ACheldU
  4202. G"tvpyC7v6UOgCA7TDqd0X6Eunzc2opHZjG6tqzjJbAQtaz6uvQvTO946XLDre75K
  4203. G"JN2SMTLSHaBiMGj91hMmb9FxhXWwNvT#liVV7C0UAGgek162mqdVzRtk6Q#f1B5
  4204. G"2gcAanZRiObAb00b9e6SaEIIGtlny3bjnaTMbNzIIA6eggzsHIgbKDGHkZzooqd
  4205. G"g0V4DQmH4GppM4i1gklopH3DTZjjafQhg4bR5hObRpaWImRUfIBtqqWJ6StNYuH
  4206. G"gKJmLgFR1ktycc1MqO8x9jVL3jay4OUi6uDF1VOEUJJeMrEkRhtClD#9otycar7
  4207. G"TTms3pdvCZU9BOnA4057XCjsS2SOnl1i95wXzxaA4o1ISleGJgeVoWohyhC740F
  4208. G"51bTaYo0Hr2bq71b0Uqdi96G#fLiyp23KeXHUa6VnVucLidH8jZhHO2PxBzQurE
  4209. G"ogrG6q2HdXXOXq5oiiUcYPqTQdUTBFZfiBCLgWNoxCtNwvMY0umLq1Ilm8WsgUs
  4210. G"X12470qvZJqrr9S5dGKn6ShtfiAy4OO8acUoGWW0LhWryCWFDajQJKObEHwS3H1
  4211. G"HhobkoCSomcGOPJ1HjhSGI8SomBgrBEwhMzd75vCjNlAiQQXGb2XDmc9LDSyn2V
  4212. G"YtbmGWD6kk8Raycza5A4hGgqT0aeO*GbayxrRaHPzXZDag)uQ*c*mfuwpvfvUGu
  4213. G"dceGeJqrf2CdAjQ528uGbsmbrfBVL3$LQeKGKTHnVVTU01LOj5niJ5lV5lXjoq#
  4214. G"n7BLlijBzPBytlBbjCd7zlZYVztRBtlDt7BDZ2Bv#YgQGGRhH1TU3nnOyfPfnOe
  4215. G"5#ByPmkEGT32WI302262wq6MH3ITmoRFRzbjAlByjZ77ZoxqyS$M7pTzoJi49CP
  4216. G"RCR7yPZ595c3Yog037z6fZ#yrByLd3ubpvHXK7i6uS7HLTYP6ppQVlRBPd76Ysw
  4217. G"qa#IO60ww2s27MwYsx0q3Q0$6625M2Z6gVpPzGNChDVi2tQrHI5iKFp232MWUww
  4218. G"DoIG$5GLB6SVP$kz9yCYok8Zf8EkOp9lsMj#Mo0hpzeFhMIHuWJNCB25eMQ0NVf
  4219. G"e3LUoRRbjrfAqNArb5p$5psM33DSLH2CoStlldorDtx2w2DKwqACnDQZbrdhAFy
  4220.  
  4221. G"cYw4hPgZGN9JGW3c5LDPBqqRlI30Pn3SH8y0BYYIhW8Dli#B4Hlz3I5dUdgeVdB
  4222. G"DzlDeVRbulnabk*e(LpzfxKB0QW4G*0c)q*WqpXumUymU4nIrn6ObkibGyHmeeJ
  4223. G"HnG4fJjIbHjr0iqjmr8iYiIpHmrulPjIxPJKqfbeHjaHJ5nSjgdSG6OHT8Lb0HU
  4224. G"0fObeSjm55n1Ho6eHevb1eMLbpLzM00LWKGQrLnKHSjnUznUiPLjItHk6ig2yg4
  4225. G"Gg40MqLfhfToLfSPQIzmLrTVeHaulnabk*y(rWzfxyigvEvhk)Whb(G*WqpXumU
  4226. G"8Kqk9(smajvyZj4KJA7XuNU9rcgeWe0uU9wEFaJqaAWX#w2gtxow5I4d8S30PcY
  4227. G"H6weNaK$ZmLPjvOdnOPeXfy57SmzlorSbo#qhWHA1BAzPG8gKOhvQpTQqnHd9Pm
  4228. G"nMFLQffRuLajprlAb$krdkvdkbiwlWZ70Pu9FvOtDQdyy$GKKKunRqTOt5#lQqq
  4229. G"2tGZp1S2uHWFqZu2LiM27rkYh4ajyansYATbybnyaXsYQcb4bpyabqYcDpctyap
  4230. G"qYoilmazyddOOswpVbv4cdOp1KqEb#$b#Fc#FbAvo3aZFGbuGcmaj9anGfnGaNX
  4231. G"MeGk8RFnmB5PBDNBzjtv$xllEtlDK6$QzVRCo#YGSdNJ3T01SaSJWgdC7OTSHLS
  4232. G"c#WHHO2GFLoEpBlRGBCyvAaJmJgk$RZLUYDSWnVa8RWEHaGkpzfRCfCKdlsdy7z
  4233. G"Cd8AUrhlAxd4VwacxyBHI2NByzBBfmRdReda6Hfl5HDyuYVugNbS92gM1oLMsRd
  4234. G"5g7n7BHZX#1H0C5bOBsak4BdsetaJx0bm6G2dYhYxWiqg0jiKgG3waYbCcsG11w
  4235. G"ZjYWehHwLHixGunGoeuMN4Evxm7XfBTMgxVQvZlN8FMFqRMWwc6tu0Rra2qcY$$
  4236. G"BqbEW3wN28PXVNHe0#$hyc1ITUM1SLvUhKG6$$b6$t70b9nkoMApIg$B4hWrtpi
  4237. G"X#eBu#NyR6$fcD6oW0BbSDgGnobvBasMuGLLtzpZzPvfiZfPvjiX$yNzEcTQdjU
  4238. G"b70135zcQAVhWtXAkh5a0QfKNGEfJ9afGoIX1nPXi2LPjpUbWY6$TR$eE#f1Rwc
  4239. G"Aa$2UAsg#sotHREqA1bs8oK$eVbd7hyyxGCEdvTuVwLQM2G7e0FQQ$mvTlGQMMk
  4240. G"f7bOiRJympAfqsgfzJwjJTz2WDp4fW97J7biFCJQVJJ4ThXk#i#0LM$Fr$G9R#r
  4241. G"kFutDeN4Ezm22f1D6C6p$$NiNBsADFTkcjoEgEMNMOSBM6AKpMHN5r1QhK4o54j
  4242. G"UsCtxeJ9FmSRtoZ8yeU7IW9veUNHWDlyTlHWVbg7hyytiTUescQNdWPiKOryobL
  4243. G"rfU9bqjpbuY0eHi$wiYEaiYOYM0Hamif7py3QIDiumpcfZLqX8jumNcfZRqXClu
  4244. G"m$cfZXqXMBOf3$$$IsOrIBag5#W4Le6g4fcDd4y8PCgtJEVU3KJUUOJTHDPnSZS
  4245. G"HDJnSdSHDDnStRHDxnSJQHDrnSZPHDlnShj14iYl6fs5rUGC2$JUZ2jP95OSpMH
  4246. G"9UmSFLH9OmSVKH9ImS$JH9CmSpJH9wmSFIH9qmSZHK#jK0oeu2zyNidMXrgEEKb
  4247. G"zj4amkKbAfEtqReYW0Jm4gGmqhM40JHmaEd8MOkwFqX#GnXBA$HNrlb8mSuLZQa
  4248. G"pNtLBnpW6ukB4uQgoLAfOuivGsrzCk1VMYtRu1w6iUWyAoLft$UIBtaUraOymhb
  4249. G"WuDhcRkJd(ZdjaJlafjaVlaST#q6Db8ha5ANAaIsa#AaMsa#BacJuLbymby9b4m
  4250. G"#SoaNAZWaUJ8dr3nzadkazzafYHEz8hG4mGefG#OwmD3ie0uFapkaHAaOfUvdys
  4251. G"bixdqyVyditbyAd4tb4Fd4ubyK0ema3CaZsdpxRa80bO05whqUcWzhWUcWChqVC
  4252. G"2hWVcWIhqWcWLhaf3JEafZCFaQfU3dyBbaDA4CKoaD1ouGYjVwGZrtFbwxassbw
  4253. G"vqlkQ86uaprylZteOhGNixapraTIg21u0a9bu08eu0aA7hzL1JpH3E9JJrozMN5
  4254. G"xck4oQZ9c5gCbbf85mS3MH9ZmSlg3WzPB3kk7sXnCtm2rkNU8bqFiIUkcqB$jIU
  4255. G"0l0MGMES5XMuYratMEimf0e4AwhV2wfaPlBwzc4KDc4KH3aozyQgROHekod1C2N
  4256. G"0CgC#naYfWVbCa61VM8L3yoD6nZlhDAMBDR2qMdm#K3lLuX62WJQHDrnS3PH9mb
  4257. G"ehsEpXnKYEGuE8Se93if2m07xHEpi07#iB$fd7PyyFed7EyyxdPFeO3pGYMB8#d
  4258. G"Qt6UbEys8snsb#aEyItcGGtTaQZWtef8c2JfHEfP8DKnTH7Zz9izTa3dhVfiFbO
  4259. G"xfyFbizf4FbOAfamRbSajmavSayOSMfOHbiPfaS5QwGjgGWwGrgGgxanXa8NYau
  4260. G"8cSYae$c0sAPf4Le7hyMsP9aGZdYb2zaw0bGz8vhiOmDEGHs14bayDFh4OkspWs
  4261. G"dWepqtjB8aBLu5FYu1l4peomA2T0mSaMj9WcKaDu0gWmVXcSaFu4lOzEKf4aGOy
  4262. G"MtZkZZNQGnft9(O4CLtXAZmfNxiZWsRqMpIEUEfM4A30UGsh0rAtwdGsAanmBrW
  4263. G"5fSf4OwGdMGcuqBuoTVzJMNgyv$Vd6K2dInxXkGewdWK6$vqzKhoeKhag7JHN0e
  4264. G"uq7uwSHPJ4g4y3SSnSNvbhlIu9fu1mE2R35oOhclOZgXXa#$ggWVtj9Zli4Chrc
  4265. G"FIA8#aXWAo2AA#88$C5k#yTV7YDdA22sx7wMmx3argJhXpSciOHQI25TWqzY#b$
  4266. G"OHEin0JGH2kSyeTI3cdubW5OkWPPWmEWoA$1qu7huULDS0npNiJ1XHZMZLnGck3
  4267. G"II7PatBZ$khuUXdUuW2gtBeMMshU14fniTejpxC1nJPfGX0eWyAdymncmMwbgtZ
  4268. G"aJPDW9aWoa3tz8nWyAh2xq7LjJBea0liJmTKfWSjLWaAAgUGegWYC0tsPNscFLe
  4269. G"Elj8xs4XKWNjHlx5bVjHNtcFNeEpj8Fs4bLWhkHxuc$O4R8yKFcwdo382wXqMsR
  4270. G"gbs7FzA1Hcob36cj0ozl7dSUL5InTKfc0xi0hMxi9ygHKXLPeupCi$m1VCK9VSt
  4271. G"O6wwk6NlfMcfa1JLTvW4Mcp21AHRPcA$cjt90VwmKCABZWuP6AiOZXRMooi1YYr
  4272. G"bRaBiUS2bVNTVrUhez12XQUUTTSKWOhTP9SOfLcEaw$DzrXH0omkoI2PXwfkK6x
  4273. G"qb3XrClkppk8MmeGFyZlq86o#2#MRhTbPOl5ZtKZYvisVz8YP2krsMH2sYxa2oY
  4274. G"2IMISLK3aLlNDitP2gYuTTH8kG9EBS4PAwncrvYQCD7zJHYiLHYUD6xNBA1JYS$
  4275. G"nLzcTTMymZIeK$tgJdiCzzdtWq#egMbW$TF1TL9UZ1iSMaXk0z7qcG3d2vj#$kx
  4276. G"tkl#AAmDPbGLa2NlnHyT4TQ1$uWAbvRp6cggBlr1FcOLQnxP$d8oG1qqLVcJTEz
  4277. G"1$Zk3IQKNP1GHWGsypwA9OqRHUGJPk7LjRXfqwtpGSMtGHmul6xxa5zBx0FqxqB
  4278. G"xgosUmKJDmCSiRR4gajJJTKrJEauojmoMeczJzxLSRrqNBaGt1Vdg2PdxC66I9Y
  4279. G"cPCyDliD7BPlikdkiQwbrpxPLrN#pxqiS5QXKo3WGWTKY3nAdekCBmh3tYK6uIw
  4280. G"LrilylzQIPhjiOhBnzRo7w6G0I#S4ws9#mHdI09UVjCOlVIYlNUa1sdqGc,qVtw
  4281. G"XfgV49Idd*m*i*m0tmfJlevKrofutfbYqpXumnOWvj5erpD1qp1eubrvdkqurtn
  4282. G"Kujbfvj9KtGCYqpXumN0GcA0GcqT0aeO*GbaqbNvCHfeOoF#h)C6b)c*d9etX4s
  4283. G"tbbvdceGeJqrf2CdAjQ528uGbsmbrfBVL3FQ0nSJDTGmOSLTVDSHLUP9TUfK9eK
  4284. G"X0MZeN0eKInV0TSZTHki4nih7BzBmqUT#lx6csqe8Z0Y62Zsx0OC3PHTTLb5wWr
  4285. G"COSnSZX$hKWeMWmM6G4hgj$ZCO4ejCx$uMgZVs1IIvQmF4FkrlI8Py$sEhtCctA
  4286. G"iFL7HK8HnMcLiLlcEld5RlAtRktdkvFQu0pCYhEziFhgyT8Rf5CqSOoLi1Nugof
  4287. G"R#uOJMifVds9jnAqIUY#WlZGwuK8DAHo1PWoySUO#6zWoAAuvsNSUMjVjil0IEK
  4288. G"1ru$KMYioHrRHl4m5JmnHzqQkZRLdr#a5yIdKmwSMuJkKTgsYh4eFijFGDrKpaR
  4289. G"RgcYh4eFiiFGZvdb5d8Hcwdysd5ZWAG8qkhcynqs#ioeSgijF4WAaMdbRbOn6cK
  4290. G"KpmLdG2Olqr#6GqjZD6ucvapRV5tktBmFZYqIuIkLSgInDQhj#4lsYFmOKzAFXh
  4291. G"yxZzyiHmudkrIpqRqshJhzH8bN4JinCZyoKHaLsyiJl#WJ1N85cEXhe45cEXhe0
  4292. G"5cEXhzAKia5X#fwoDBBtb7fFGlnIp1wOd6qxY4GI1nA2#tLBApBAGwEu5#26chJ
  4293. G"rX4MhvQpTQqH8ju0EFw5CWQbrfRMUYnVGeUV59LjRQHzHWMtuCyWSbulnabk*y(
  4294. G"uWzfxS63LTMzy)nvc(G*WqpXumUuewf9(smajvyZj4KJA7XuNU9rcgeWe0uU9wE
  4295. G"$MQ1MgWjCStGH9$$VH3wxtcK9bOdOHDh#rD7qas7e28qI7aYeINQOnTZfKWvUV9
  4296. G"SYnSTfKJnSU1TVLUGuU11TGmncprF6ubzBFlzlRlBydvijgAKoTOfuHSfGceGVu
  4297. G"W8uScuGdqV5yFGbWyB5cUJhbjLJLGDWcqXcq3fppbd7b4FujV03iaBWW2YkdDTa
  4298. G"HiaNzbdydbAbj4qFktJr60iqV9HguMY0PuMTQjcgWtEvxm7XTcbOMrOb49$Qw1J
  4299. G"OvOay4lIZd9euMEWehHj2O8pXw1$le60DGP3cy7ob7j8c3b2obvBa1Sqlycs2fO
  4300. G"JnihjOjnUbbRaLPjpUbc8JW1TR$eE#b#QLGgenvVMzFcXG5odmFpyUswbsLI9Yy
  4301. G"Em9LfaFVz#EqUrnL2s9OvkAvoarlzUx119GOaUFaDpU0Uh8K7EsXCVECJQpLkI3
  4302. G"EeR4tlF6uC$Fr$G9R#rkFuY3qasCVApN3Er9heGP$8$tSheITK#eHRVtCTf7fx7
  4303. G"6naCTLnXN9bPy$Haeef7qOyEekMlHI5tOyofkMxHI5wOy#fkMJHITR0AqZ0sl0i
  4304. G"rSBT7SCgj2odK7hLDTKbaDt$o6gAHq3a#efevKweITIuagg$#sfN9KW3AnfaFZY
  4305.  
  4306. G"MBL1Ry$kf7d2e6M7VIgTewFKu06fdqrd#tv047POHoafnxafnqTYcOObFRkA8Gv
  4307. G"0qpGIMNGIgOoDbye5Zc31q93U2RFpb9ttI#vTkWHCnPv34ghqUJDnx0BzQA75Qa
  4308. G"kZAxfWZL17vbK1inqwVwqC1y8UZGQXkA0aPOvO4mb5lfYf$#Q53iv7a8BGUM8BG
  4309. G"Ab8BGkS8BG9x#nKpPpRE9RjFzx6GL$JcW6e7r8dWKMOe3d4Ufyaz8hhm59FIplb
  4310. G"X1tpumEfEFOvSBaHtuFtYFac1ftClcvn1lqXQHb$O1zaXnpdOhEMgDobhQgCDo1
  4311. G"y$a31Aw3emLe8$2mom128nd7TzyFnd7Pzrl03ft1oe90hG460CBK7U$2DUao7do
  4312. G"ad$sG7m6w#$BHPFx3MpdwtZQo3$$VMeW9eG1nGhXyLUY03wmGlo6lE5Z30lw50f
  4313. G"HZe4Y31098RVd36FWfF$p#7GgWytqwZYGkNqbdEjDSWYFHR617El#XH1vrLhGsD
  4314. G"XuhWNs8Vfq2NsqElkL5IVqGJ16cXydKH801G8uG11GXgHi8rI$sZR11IwpuqFUd
  4315. G"vD7uc6qPAXP8MPX6IDOdj44t5ITHvDXonNGmw7ZC728$EKHeCUfySpDrQBdQNcu
  4316. G"77YkBvltVVXib$LWJ#kdaKjzmaxwGOpZKVEnySNRc9xVeo2T6vZ1C81JGKPdyaJ
  4317. G"QctEDLOVPzb$LWJEUGptwA0XWDFZbK5kbz8GOgNLg8OeWVMUreRkK8qTUlWvjkL
  4318. G"RBb#vstyhH80BAVUnGKvmXve0XfO$Qx76Y8l#busMxPdFN3FUoCWVNGlUGlSOcK
  4319. G"UY$$Din9W#eiH#wsOjt3N8X$PtG$EGtoQahDTSFXLtOhx8F6HQ$ZQw0sVsSlhpb
  4320. G"7rbhGY4lE8snQlt4dTFdiqcQUtNEyu7TlwERot7Nlq#ltYZFwltWl#9dy6xv6#a
  4321. G"I#o$pQso#WkGJDVU8hBqdhGHhXbmu6U7ypqfFXW3jgHbmFC7R79TzIT5CdOnzSh
  4322. G"U93Y2JOQydANWbCMs$x2pRfQcbED1pR5jiP7#5zcP79yE6o2J6eNv25SJoNDQYt
  4323. G"rsxsYtUCWDHUE0XgpiANYRpPDcoWOV#RV4Gh90pXOJ6awxNV#aqFS7NiBxyStdp
  4324. G"2b$3yhT1x$NA8pX#G35bE9Jg9Zf8l#4du4aLK#h9qpGZ1G4IM2P3N9FuC2NylqA
  4325. G"$IAOo#DSWnzI$Pjz8reIpmUy0LLLvwRQ5sx$a6sRk8c26KoIGmhCx7C7AxlbLFc
  4326. G"QsvvqgAdcBUoVOVAfNv1XL3dBrW8jJiZvb3#VENIidZ70D7Dsp9UgTGYCf8byf6
  4327. G"hZUR4QYPgsi0fdDWShHE41uzubJzSx9x51h63SDZ$Vj1zbm6in3OUQVIoNC2n6I
  4328. G"9F0nxWJERdq5EHwgJprRno6AuxUmC0VXpBR6fDJ5GsPY403s#V4NTKAO$lzg#ht
  4329. G"64R5IwK3O#3K7aNxlXDyuoT$xhFUCDE#NIY5SC94NUl0XEvFiPosukp$yt0IFzv
  4330. G"Rpmr0k$bCxfaGwCCJlWh7og4l2Qg0xeQ36DkC6crGAz6YWl5wPwwz1G2RF9wAQZ
  4331. G"Dx5c4D9k2YPXE0x8$vA5FuYlwFLtE$ONebnRWYNQhODsrMCRFHEQ6vd8ymbpSdv
  4332. G"$aJI2dzm#4cUfqNwow1xiYiCo$hSRdB1ylKJZm4pglydnycpidridtidv4bxGXB
  4333. G"XgAXh8G7ggrjkrbWX#G2WHkqP2WP2WR2WSUq22aomdxok3eSNhWkmWkuWjKWnK0
  4334. G"l05c86l4a7i0IJUh2j3gGM#$Z0ywrNIBkJLTVBcMWCTJjeDFJUuNhKUwCOdv83N
  4335. G"NtuUeKNK0UkCO8Kxi7k3UbCOUuXhnGyEuc9dBWNuZaMIkpbgezmYVsGN51NrirX
  4336. G"3c4BuIBhp#UceocYUb1S#zO5tqzlV6sm6HY2qZ5ekFeSnXtpbKJVyJ8lyZYWfJ8
  4337. G"f8kEyejqbrEdUiO#fk96#XE0wtxnWi8bIC5srOoLpXro6vZG#ixRBfRRm4dwBDY
  4338. G"ZZbV$aE3c0ehWR7W6LF$ShfXnr#g48VeoFNpxUyCGzFUmKXbpWblP3XbtN$RNeO
  4339. G"Tw3rVE(38jUyNY$vImdJmE$VrLzl47rwjy2tnde9zGfzI0#FZhnLnElcjNU52NO
  4340. G"kKbckBVjethkLOKB9XLdTKlRAhbvtBZftezj9L7m42r#d2tDu4K2GtriVa$pnm9
  4341. G"gYqGJDj#Nf#YrEkk$bI9asaI6fSiCHN#bDwvulxOu0iNW9UhTs8lQows8wuFDbt
  4342. G"MspDEv12h8vkmRMO1Dft0fOk7CEbHmSYDTWMuAW1r7CDDrx$6j13BsfFGKMrU3M
  4343. G"usUbi3gxP4qtcFzuT5igF5PxV$hWmvHGOoV$KtvNTtFcrkJBmzZYr$xIyyCXXFJ
  4344. G"gdBrO8hOUMRzl$WsNGvg2$RVN5xPxOb2grV#oT1LdPft2G$iiSwHOwW0LSO6w4G
  4345. G"94eHcctvUfJrneP7uxmtAzmdy1NHcKKVhrINS#b#DDXd8XmJ9YzfZfWZi9srnbR
  4346. G"lgusEDfAG93xhOwfpPwEtA$dPZEGKAgghZY8g5W9RoLR8Fwb8zlLJAemB7iRRVm
  4347. G"1MBv0tgl41Tefv6SWOn3PIQZkxOjMIlUQcuPjMkHCVKrnkfPwYz1b0UxaAnReNp
  4348. G"7vY6Bsexb8W11wyrJItZmY4EBzw6XNlBJ0ChkR7UebRBwxU3R$zTCKyngzEcq4z
  4349. G"j66QxywxS3d86qY#WqYX7eAoNYraHKC6Tdu2jGY2zvpZB0Jzdv1ED5ovAPmrnqv
  4350. G"I7L6iocOHPD7vGDWXCpVZg7r6DrildlDzklJiDsn103CaUs7BS3WbqG5#7Odg#v
  4351. G"q6kG$H5VLmM5qz6wL650b5Pr9#kPlhz5nyCkDJRF9uhY#k3j8nJ6IL8jiH#0hY3
  4352. G"3yu11v8dIu7bBE$HT5BDSIEa44n0dSZ8a51xQL5eBz76ZmUSJTPRwr3GKHvK3mG
  4353. G"W2Q9TEV7JoSJg54gursC3VqixyDwEb5ZILJp908hXfjYFVIphyS66exKZCe0Q4Y
  4354. G"#cqCV5lI7PFE$cEVJ0Ej1dAcUB4oavFEc3nDhqRphlvEiQn5iXXth6Ioi#vfGUb
  4355. G"pe9jBikirxafrH4k7io0OlqJxWiWZWYuEkybYq3WTULNGFWefC7$6rgGF8bFy3n
  4356. G"PbkB4laMZTaWHD6shcbd9diUcymVE6kH7hXfijlW9eva7TsueC0e3HfWD4v#pE7
  4357. G"r4cU9UUiOoNT1WXV$lCT5BBR1KCa4e8FA$GvzFd#8O86y7qZ3czUVII2edPe3VH
  4358. G"ekpo0kMPluLTpQAw6wSSpi11ZX2rxnzR$6m2LAPvSz46v#y$jcxkk6diax2rH7R
  4359. G"VoL6ef5fmH69T7FWgNH50MSDGY1cdrFW0nEs51SSDyvDWu2#Y$9JU#WLLnQyF6F
  4360. G"SAz1FrnxyeXHS7Fy#F4dH4qH4BH4DHiOHO0HqHano#OD0Ap5ufPi9DeB09tmvPn
  4361. G"jRteXP8#7JUBaKUqs3NFDh$PVwk#J3bYsqYtSKj8RtYheloSbyShGl6fq8FD$hC
  4362. G"PJU8DmDZ8OpEx#$tB4hQivbPB4O3gishlRwHNWBpH3D318hKaejip9x$MA92$8S
  4363. G"fN8gqEsj#oMNRizgG9ecHY19aj7cm959$8CekZbC6D7$m2ry6p7$v0RWbC#vzDF
  4364. G"ahMhqw88EX7JT#5pi8HPmB3xT93Tcb49h$adMA7PFN$tTJe#wO9mMhNHOhfZRuq
  4365. G"r1Ghn9Ghn9txaNGkLngfhIRxK80ijZKvhJ80jjR9B6DipzsYm4EcuS5uJD$fVs2
  4366. G"6SAnLdiptJXEJm#6ySvB1xkJ9ez84Xy7d788ng7IY4htlN55CYi6ULUrLNWLUGL
  4367. G"NfbWBEEeiRt$UkRRfAAflWg77h7FlEqv$e7KN#4hajEDQMo2LiJb2IaRgIp4VJw
  4368. G"H$o8ASxgVWS3P07a5YGhwBuWpnRRm$h#5PFyTVyfWxWxT98IDA3jEFv$593YomK
  4369. G"5n6LrL15OieG1gT$ySUWas7$FWCncqL9srMxU9x2$#Q1D0dBbeTX8s2$yz6Ewb1
  4370. G"O5gEY#xN5cHy75EhL7QKCNhi3R4uln9njcYG8Bm5aXi5mee5#dVtVIJ$3juLlpA
  4371. G"FeF9kSNNzcoo9dG7mr1DNWtFRAblsoeQvTNYjiDMJ7HwYpyJ6amMbAThz$as2ie
  4372. G"AABY#5IiMwRBcC3YaRu26G9$zuH67LTrnj8OwUQSGWgCVGh5j4bWJOFLhNQsnLi
  4373. G"Fna0kbiV#46RHrwOdvSFITMhbQA4LyLZlFyk7OkaF5rSvNN52NVXnBZxfWZocwI
  4374. G"S$07ljhN1ThanBvMpajYvWzPPm$b0Q33fy3YGZdwAeURn3s77bAZmpp3S8$EiwV
  4375. G"qT5Nv4r4KdNxxALHZ6t21csJEGgG9Snd9oC8gGVCy0z#t0a8ccZGUUWMogBBgSS
  4376. G"TYBH#2s7GWAdA6van9dG26$eaTdcOz222gJxrY3NSAGvZ#O0T5i2H4ix2GeDxUD
  4377. G"c6hyVxEVEdF0hjkikBdM9nOyNaFZHj63maZ6xpWN62rBgti6Pn0UBqa0V#o0KT6
  4378. G"xFhomK5lgAdVKAwm3IzpcrF6yjTWQP$Wrp2WvgFCo#aIq9W#CE4yIVtJGBY$$uc
  4379. G"IxiAYfHbBXXnPJOyVQGeABFuLsdZoP6f$Eg0CTMftQEDrNgSp#neJQcOgF0Qzc$
  4380. G"Sg9aZe14leBW2$v6iNC8b#dF8zyBAflC0tQTbB$V6Kme8Fv4c3MJrh4Sp71OKOc
  4381. G"F$4pjHxYhE6eeM8mN2jevQ#R6flCNUEST49Zpk$hMmbyiezqkU$8iBzsjiIBcbr
  4382. G"TUXZxKBmLRJJsueGWNnX3Go#U$CzWiSXij2LCnngc7nWai$JbqEH6A1QCqD3qOU
  4383. G"EPxy7lM5tbcnggIJsi8mzqUqOPdpGpLoV7FKEGfl9DOI9Jp1MTdPMbbaWG2Vnqy
  4384. G"ysfqUYEPqSJVtdxkAO3j8kh4aOGYt1p89hhWkhch3G$QG4m8wemxb7B0cFREAOu
  4385. G"udfjyPC7eugb4ySWCHFa8JxYbOa$hRBefyCl2t3KywS9ch#6kXQl71DeS9$1Zp9
  4386. G"mQX193jujL9gGoTUXaw2xp5c8kX9g7v6pfI7pg27Cce0cnHGkZf8kQbKrhXnG$d
  4387. G"AFdUn2UMWXgWi2PYlsB6ZJDEFasNPpqtFHbGiB3ak7iC97PwPr#tFfMC6wVe9vW
  4388. G"D7Rvk0g2lXgikATRpT#7tbUIZWEoiQYtplNhF7h5izI2dff2IFtbKPUG5CSdHRs
  4389. G"a7x7RHlTLcFE#j86tBCJlL0ScfPMEKwyAUS#nNEMmhP1ffGrmL2EsC0wHVRPgFE
  4390.  
  4391. G"DW9aozHQMfHsMdsfuKR4OJLAp2r8JSdrh0qJdw9H#id2CEuzMlCRgACgy4HJadp
  4392. G"6ZkpnC0sGaXjBlFqdAuu7Phk4UDokdBju9#G4U#WbDfwCRIWzC4qYpngbc2lw#j
  4393. G"2S4t13h$pHTc2e4s1dbG4AMVyeHpSNOgG2LPFaGUVyURRz$7jkf4CEdzi9kf$IP
  4394. G"g9bQx8wmGRam935#84TQfNN6OiX$pdqy5SnwJEocqvT0$VtBx8Od0pi6nqpP2tp
  4395. G"Mmbp2umgJx3PcN7rd4b8pZh9JpKrHiBrGiRfD1rGSJrN8iuDpYvB$oZUCoaSnym
  4396. G"3#HzuPtnjSAD5HzWXypYHl8UvWga4zR1DD1216UU6yC#xVjmBZKeTdsox8MSZ$G
  4397. G"m0huDiM4MCUV3apWkjMMBUOIXaADrn9VmEkzBgAR5uGy37HUK9uiv9fEQev$dYT
  4398. G"Fb5gwMj36XKBF9cBHH9w#TQBk5ETBc5wY02uXnF9JcWWdTGd4oj#Cp4kjgSWS6x
  4399. G"g1E#vFQXOnVWjcMP8gOaShFbOFM0JAVOPZ8X7o5MY5h93nTEm0E7MU9I8Fd5mUy
  4400. G"BA#bwCpc#bGskaUFTj1N7kqXCX$kd3P1R77X6h9iXTb2DlxTFGp3hW1VJaGoBtF
  4401. G"G$pd1Wq6Fr8RttQLdORMFvS$Gg8xGp6bNRxcH7la$)l#bMiP2M5$hKQZeoCIHyv
  4402. G"IpW9N4$sWN#0wi7DJVlfpEb80Z5van5jiJydBmToEXB8Fni$x9Qp6rozyg$Q#eD
  4403. G"tidbDcnjJ7QanzI746PWHWjguOMNl9cpXCbe4pQet0kHpa3wfHtCxS27I3D8eC4
  4404. G"bfWH3$tPiKeCV4VGOhf5h5Ih#wrffK2pKFhWWFfH70BJW9sS2ziKBmvc8E6Zn8d
  4405. G"e#YDKTAechEvOgjjq9ChXZwiqdTOfW0cVac61iiwP93QMd8TU4JCl9rrWP$zCRj
  4406. G"ckMk3hy#a5wFDbQygYDKhbczHN$r9Q2lgANUMf936#QeNaeTpaoqojSwT3jc02N
  4407. G"UpDGoFUjOlVUH$$h$mxVqXTGrGiVnzOv$a7jaQm3ccwdiU4Y1Grx91bYDroitMl
  4408. G"3ogTeRfossQmi8Cey73x6Ju4sHbIbOwNBd4E4fZFC1tTE7uQw5n0x5vCHLfu#Dv
  4409. G"qk4trHoq5FCcKfnM$RzDyDNtzcS$Hk5VDNa5VClyoVQ$Nlgfku9GKk#de7cNtG8
  4410. G"l7W7dy#h#vWt#o4Vl7CtER7bshMWqYrdsuPxV8WdPK#ls9rFWc$Kaw8WhQlM4sb
  4411. G"titPzd2EDPWbSbhmpG6PJQh9p0Fq0dQPsC0fFTc4s3E7qdSZySnNJ#8KmfTVF0j
  4412. G"2dWzGOXKlqsN0ON#5x6jM85t6fpVgJ$iJf2bx6RbUXo6KeYB9fYJsWEh6Hm1hps
  4413. G"GAlOfIqONx6vk8nU9roS4Wl2AlJeOrkmewJh5XJHGq6c7VVGBvHogBcynhig4fe
  4414. G"2BOPE9#I0meGCemB8h8AtjpajCaLGJYaCYymalBhp03OaoMNtnoGJ9bgWBfbXaS
  4415. G"ah7h1chFIo21X5UII#aU7nC8i6zhah7I4yV2A44nXXUgyHDagJJD$9URJJ9xxHJ
  4416. G"Fhh7I5zNih7g6z3ih7w6zFjh7i7zVjh767Eplh7k4yNlwLmmG$VGbCq20PcsPwx
  4417. G"32sQM22wwqY00kw5gw5Mxq2sqo03c38k30Ew0sxqIYXMsqgZCMtyCc2nnTJvUVD
  4418. G"UV1mtx3lx4Sq97kgEbxgbO2LJ9TSfGdnSUfKU9nzN9xgKRAfKMnTSTSaKQOnTZf
  4419. G"ec70nT0P5Ko7hKWnSNb5FRB0gisx0k3YW9KmPoLOvfGbjylzQIPhjiOhtUVnU1U
  4420. G"LoiTOplU1062Zeois37#MWHQotM0cuSwGMeO$6q$Qrtktl6xE7n6taLBWUsnjyG
  4421. G"rJ8boWbQAqRqfemi5pWC1f8a9anJRvas5auSsscgGXHxamdVafWSlGV4aOPiJMa
  4422. G"UQHRaoCrAaHfGKLW#bC8guGqKGfTOfTGfiyVMWycvGRGeKWeQy9aZegMWeMxfQh
  4423. G"4z5EocblycwyAhU4fpbpcc3bq3JqeySjCeRO0T1LTSnLgyVbZVahKc0apcA4Dhc
  4424. G"KBq5nSBVHD9nS7$bSeyYUWeSlZhS5OCKGEKGGKGIKG8KNobu7J6tFC9s1gqL3qf
  4425. G"OP1H5HDSRj3C7ww5Aw2#27eDHTTToJTLqZonJqVwZjBATBAjJMXIrrn5TUYaxXb
  4426. G"4YOMyz8BRtMAhDV6pMEdkz1pBDyn05SUNG155yDGa0L1vOSBCxA35pai20Ilhaz
  4427. G"NoaYIE32nECUgrRYGOLXYddUU2s4#gUYq6RJFQWNoBnlBBSMmaTha35XyUzdrhe
  4428. G"QZkYEyN7CeKsTXOs#aWAxGeaKfTJdailA3oaqwka1sdqGc*gaGMCwXf8XkPxjrb
  4429. G"(GQr)g*m0tmfJld1GabiXiuuHn3GwIAUnpfyGetquX2B59hzAD7yzBDjBzbjpNl
  4430. G"DjBAFRlrRpBOcMo5yPBEHBzMo8WvUVDSLDUZP6W1$wolVpd1ruKSnS59T1LouVf
  4431. G"b1Xo23YMOBbpQ$RZ4Aqi9J2YgwYccIN7O6yPBAPlBKFvC76itwXkxqm8nDKNByz
  4432. G"BBbbXJQJKW72y8n9i49lvjibPtFkvlQomEpeP3WnnA7M9niRzAyL7zsE323W1nB
  4433. G"b5ldkt4EdYqgYqq8wLVyS1Tnm6DJYuC8EpcV0#bPrtktlY2lR6MnnuTn9CSOry1
  4434. G"0BXwxZA2YkhPlMF5Von1ZAUBwuIc5l7H8kPubTwK0zivz5cSVizPiVRyfzktji7
  4435. G"zpbjmm3tW5EcHdtATViFp0W6wq623KSs#jiIFccHfTVW2tyzXJvUrzmuU3NYP#Q
  4436. G"p3Yi#cUdK30TUYDmdF95jeoipPmpjiwwtgMTLvLD3s2e#A6LAUQ7UTZ5SS#h8P0
  4437. G"LMTT01odvT0f8ZDCDCtRXJA3H56hgvxA27i2fu3O0eDpz5CtRElJ1Au0eqmLSmM
  4438. G"SyUKPajtj2IOGpxDCLxuhnxH9ETPfolxn#DSIXPDZwtvD3LYTmpowxNuPRzzxd3
  4439. G"WEgRNOSUUrP7ZOvnzIIEkwB2v$Xc38Ic1RkUnNAQI20eVs47DkdFmmBEvxsjwyI
  4440. G"VASGM1nYcAVnauz82amPlAixf3aGrfLLzZV1xjrk$eU8iEYOgBYgw6ggVdh3fRR
  4441. G"LZM7WwPSommvDEO41wDFuMgc3KfRwkHm0uFNstCPhPvfP2G4VHw2Fk0#x5kmTcx
  4442. G"tbZRNL4fMWq0LQ8lpHLONG3flCa71zD60KY5M32kgQvgwho5RfdLtN2XK8MT5HT
  4443. G"PsDcWRM8R6uArX4IURYInjtQtjAveIl#rz04mRtJXKg4vpVBBDE#fBzqhPEARbT
  4444. G"mHjmbPtgeTthM4Sj8l2WoNLnJT#xO55OTIx2$ZfndPMo8hUZXYBCMLWip33Kjqt
  4445. G"1fI6ch7zTz5xCZ8G4MlRhfZ4FTf76u7Bqk1Nofk1726auLqWM2#sr3WohPgUzv1
  4446. G"YQyNq#XsxB86XuErteVyKuB3UgAVXhIBFnwZ3xaoDBACA6OxgxxNnss5x2VoMtH
  4447. G"dTtqezYYoTytlzWo0YtfuQasDmUoylJRdnkX#mk5kPlXbPSNYrO21HrtyDXPOo0
  4448. G"yC$Acg4n2q46XFxVhkeBA5YG3UE3YymytjQZa$a1HcOvulcg2bnDV7BwSbXb5Wg
  4449. G"fXc5WgvHc5WMcix7u61yyJ#pdBasSjk#UKIDycOD0G4maFBNf2QqHnEPZJaqYKd
  4450. G"mfCafrotZrXr2gpnkb5ztRDQZBMLH9klvQykVGmf$hhpUqNh2WOZdCowxMvBkOV
  4451. G"D396xvpULZPKOLWQVJHfHPHGB2PbM5Hpmp0KWG3WyUhJ$teEtAd8ulp#o83DTZ5
  4452. G"GLltykJeweKrw4JYiuQE0QcEgz0uOZIPKHCmuYKYqjd#YqjtpdLmQNNHsgyNJkp
  4453. G"jmwYOvi0eHDdeknMUaKspLnKB0uhMcyozkiMH1mAIjD44sPBItkRMWRAY9ibXlA
  4454. G"gXeeeS2feqfOGErmgjc$eJyhYUc765y8QOeB8H0i3zJoKJCkG1jOSnpidjE1qnT
  4455. G"#TjBvMArX2457VjEd7LvADzfdKrxIXTO2Gmb1gqb8MxutJVBlpRH3rIlcca$2Iq
  4456. G"H6ZhbKKVyplilemecoTjGHjTOnHA3A0MOTrBcvibNfcWbqT0aeO*q(WrwECb24#
  4457. G"#Fid)yp)Gc*svuqe1urUq0tdrf0KM5acYmW1aIX8g3qNWKg3qq6GMYaItmKtaIj
  4458. G"ggYug5acZKg2ugcAM34rjsXPKMZ4MWWgqidxidqeg3qgAkM3yhkQq2iYXqN0SWg
  4459. G"OaqkYpAY2eg64cqaIKqhAYM58MeUWg#qcggqmNW0g4Cu4iN3Cg54vqiXLMq5uML
  4460. G"osAAvFwgGku38XqwgIEN0irUMN2KZPYcR2M2uggQvBcc4eMZqXGshrohxquIsLQ
  4461. G"Y2nwWLUvZm22G2jExro45ugkoK3WgxqK3mgkR(qTuacS(k*y(e7yfxejXa4wah)
  4462. G"Gqb(C/ab(i/m0tm5crpneulfGalaGc*gaGJtwXft1cLniCb(q$r)f/q)c)Gjh)d
  4463. G"9etUGeulfGalaGc*gaGDfTceMMfp3by)qPc)i/q)c)Wcn)mfuwpvfvUGeulfGal
  4464. G"aGc*baq5twXf5gTkmoi*T*e/q)c)qSo)d9etXa1sbiWcaO*GbaebNvCHHyu5vDO
  4465. G"*Fe)c/)G*y1d(WqpXumU8Kqkb1sbiWcaO-07KvCHXlEV4W+d*c/e(G*Kzg(WqpX
  4466. G"umUqurgb1sbiWcaO*GbaqbNvCHfeOoF#h)C6b)c/e(G*8Eg(WqpXumU0uqqb1sb
  4467. G"iWcaO*GbaqbNvCXQFx2AMHb(0uj)c/)G*mbh(WqpXumUuewfb1sbiWcaO*GbaOj
  4468. G"NvCbFSs6vsu)OAe(Gb/e(G*8jn(WqpXumUmeulfGalaGc*b(hz5XfyJ77$Hm)G9
  4469. G"*k/q)c)q15)svuqe1urUq0tdb1sfy,kaGcaqH)qX6+a"
  4470. N=15599:K=255:IF LEN(C$)<>20799 THEN ?"Bad script!":END
  4471. FOR A=1 TO N:LOCATE 1:?STRING$(50/N*A,177):IF L=0 THEN GOSUB G:L=6
  4472. W=T\P(6-L):GOSUB G:W=W OR T*P(L):L=L-2:B$=CHR$(W AND K):PUT 1,,B$:NEXT
  4473. ?:IF C=108 THEN ?"Ok":END ELSE ?"Bad checksum!":END
  4474. G:I=I+1:T=INSTR(T$,MID$(C$,I,1))-1:C=(C+T)*2:C=C\256+(C AND 255):RETURN
  4475. SUB G(A$):SHARED C$:FOR Q=2 TO 9:DO:S=INSTR(A$,CHR$(Q+38))
  4476. IF S THEN A$=LEFT$(A$,S-1)+STRING$(Q,97)+MID$(A$,S+1)
  4477. LOOP WHILE S:NEXT:C$=C$+A$:END SUB
  4478.  
  4479. '
  4480.  
  4481.  
  4482. Msg #:  981                       QUIKBAS Subboard
  4483.  From:  EARL MONTGOMERY           Sent: 04-09-93 22:54
  4484.    To:  ALL                       Rcvd: 04-11-93 21:29
  4485.    Re:  COMPANION PROGRAM TO VGAC
  4486.  
  4487. 'Part 1 of 5 parts CLIPEDv6.BAS
  4488. 'A companion program to VGACLIP.EXE
  4489. 'Make sure you save the Document File that follows this post!
  4490. ' $INCLUDE: 'qb.bi'
  4491. DEFINT K, P
  4492. ON ERROR GOTO errorroutine
  4493. DIM B(500)
  4494. DIM d(100)
  4495. DIM PIX(1000)
  4496. DIM inreg AS RegType
  4497. DIM outreg AS RegType
  4498. restart:
  4499. SCREEN 0: CLS
  4500. PRINT "CLIPEDv6.BAS": PRINT "Copyright (C) Earl Montgomery 1990"
  4501. PRINT
  4502. GOSUB keyboard
  4503. begin:
  4504. SCREEN 13: DEF SEG = &HA000
  4505. DRAW "c142;bm100,100;r4;br2;bu2;u3;bd5;br2;r4;bl6;bd2;d3;"
  4506. DRAW "bm2,2;r6;d6;l6;u6;"
  4507. GET (2, 2)-(8, 8), d
  4508. GET (98, 92)-(114, 108), B
  4509. CLS
  4510. OUT &H3C8, 0
  4511. FOR k = 0 TO 767: OUT &H3C9, 0: NEXT
  4512. DEF SEG = &HA000
  4513. BLOAD n$ + ".cap", 0: DEF SEG = &HA000 + 4000
  4514. OUT &H3C8, 0
  4515. FOR k = 0 TO 767: P = PEEK(k): OUT &H3C9, P: NEXT
  4516. REM Main Program
  4517. x% = 160: y% = 100
  4518. cursor:
  4519. PUT (x%, y%), B
  4520. inkey1:
  4521. i$ = INKEY$: IF i$ = "" THEN GOTO inkey1
  4522. IF i$ = " " THEN GOTO inkey1
  4523. PUT (x%, y%), B
  4524. AA% = ASC(i$) AND 223
  4525. IF AA% = 0 THEN GOTO mainkeyboardscan
  4526. IF AA% = 71 THEN COLOR 15: CLS : SCREEN 0: DEF SEG : END
  4527. IF AA% = 83 THEN GOTO preparetoexit
  4528. IF AA% = 72 THEN GOTO helpscrn
  4529. IF AA% = 90 THEN GOTO zoom
  4530. GOTO cursor
  4531. mainkeyboardscan:
  4532. IF ASC(MID$(i$, 2)) = 75 THEN x% = x% - 2
  4533. IF ASC(MID$(i$, 2)) = 77 THEN x% = x% + 2
  4534. IF ASC(MID$(i$, 2)) = 72 THEN y% = y% - 2
  4535. IF ASC(MID$(i$, 2)) = 80 THEN y% = y% + 2
  4536. IF ASC(MID$(i$, 2)) = 71 THEN x% = x% - 2: y% = y% - 2
  4537. IF ASC(MID$(i$, 2)) = 79 THEN x% = x% - 2: y% = y% + 2
  4538. IF ASC(MID$(i$, 2)) = 73 THEN x% = x% + 2: y% = y% - 2
  4539. IF ASC(MID$(i$, 2)) = 81 THEN x% = x% + 2: y% = y% + 2
  4540. IF x% > 300 THEN x% = 300
  4541. IF x% < 6 THEN x% = 6
  4542. IF y% > 180 THEN y% = 180
  4543. IF y% < 5 THEN y% = 5
  4544. GOTO cursor
  4545. helpscrn:
  4546. DEF SEG = &HA000: BSAVE "temp.bin", 0, 64780!: CLS
  4547.  
  4548. DEF SEG = &HA000 + 4000
  4549. OUT &H3C7, 0
  4550. FOR k = 0 TO 767
  4551. A = INP(&H3C9)
  4552. POKE k, A
  4553. NEXT
  4554. SCREEN 9
  4555. COLOR 12, 0
  4556. PRINT "Command from main screen:"
  4557. PRINT "<G>=Good Bye  <H>=This menu."
  4558. PRINT "<S>=Press this key before saving the picture using VGACLIP!"
  4559. PRINT "<Z>=Go to ZOOM Edit Mode."
  4560. PRINT
  4561. PRINT "Commands from ZOOM Edit Mode:"
  4562. PRINT "<D>=Pen-Down Mode."
  4563. PRINT "<C>=Increases color value."
  4564. PRINT "<->=Decreases color value."
  4565. PRINT "<F>=Changes color to the same color as one block to the right."
  4566. PRINT "<L>=Return to the main screen without saving the editing."
  4567. PRINT "<S>=Saves your editing and returns to the main screen."
  4568. PRINT "<U>=Pen Up Mode."
  4569. PRINT "Use the arrow keys on the keypad to move the cursor. Home moves"
  4570. PRINT "the cursor up and to the left. PgUp moves it up and to the
  4571. right."
  4572. PRINT "End moves it down and to the left and PgDn moves it down and to"
  4573. PRINT "the right. All keys are repeat keys. Just hold them down!"
  4574. PRINT "Press any key to continue."
  4575. inkey2:
  4576. Z$ = INKEY$: IF Z$ = "" THEN GOTO inkey2
  4577. SCREEN 13
  4578. OUT &H3C8, 0: FOR k = 0 TO 767: OUT &H3C9, 0: NEXT
  4579. DEF SEG = &HA000: BLOAD "temp.bin", 0
  4580. DEF SEG = &HA000 + 4000
  4581. OUT &H3C8, 0
  4582. FOR k = 0 TO 767: P = PEEK(k): OUT &H3C9, P: NEXT
  4583. GOTO cursor
  4584. zoom:
  4585. GET (x%, y%)-(x% + 19, y% + 19), PIX
  4586. DEF SEG = &HA000 + 4000
  4587. OUT &H3C7, 0
  4588. FOR k = 0 TO 767: A = INP(&H3C9): POKE k, A: NEXT
  4589. DEF SEG = &HA000: BSAVE "temp.bin", 0, 64780!
  4590. CLS : PUT (50, 50), PIX, PSET
  4591. FOR y = 4 TO 164 STEP 8
  4592. LINE (100, y)-(260, y), 142
  4593. NEXT
  4594. FOR x = 100 TO 260 STEP 8
  4595. LINE (x, 4)-(x, 164), 142
  4596. NEXT
  4597. x = 160: y = 100
  4598. X1 = 59: Y1 = 60
  4599. i% = 1
  4600. OPEN "r", #1, "zoom", 1: FIELD 1, 1 AS O$
  4601. FOR y = 50 TO 69
  4602. FOR x = 50 TO 69
  4603. LSET O$ = CHR$(POINT(x, y)): PUT 1, i%
  4604. i% = i% + 1
  4605. NEXT x, y
  4606. CLOSE #1
  4607. i% = 1
  4608.  
  4609. OPEN "r", #1, "zoom", 1: FIELD 1, 1 AS O$
  4610. FOR y = 6 TO 164 STEP 8
  4611. FOR x = 102 TO 260 STEP 8
  4612. GET #1, i%: i% = i% + 1
  4613. IF ASC(O$) = 142 THEN PAINT (x, y), 143, 142: GOTO skipover
  4614. PAINT (x, y), ASC(O$), 142
  4615. skipover:
  4616. NEXT x, y
  4617. CLOSE #1
  4618. x = 176: y = 88
  4619. flag$ = "jump"
  4620. LINE (170, 180)-(190, 198), 142, B
  4621. c = POINT(x, y)
  4622. IF c = 142 THEN c = 143
  4623. PAINT (180, 185), c, 142: LOCATE 25, 30: PRINT c;
  4624. inkey3:
  4625. i$ = INKEY$: IF i$ = "" THEN GOSUB putcursor: GOTO inkey3
  4626. AA = ASC(i$)
  4627. IF AA = 0 THEN GOTO keyboardscanfromzoom
  4628. IF i$ = "d" OR i$ = "D" THEN flag$ = ""
  4629. IF i$ = "c" OR i$ = "C" THEN c = c + 1: IF c > 255 THEN c = 0
  4630. IF i$ = "-" OR i$ = "_" THEN c = c - 1: IF c < 0 THEN c = 0
  4631. IF c = 142 AND i$ = "-" OR i$ = "_" THEN c = 141
  4632. IF c = 142 AND i$ = "c" OR i$ = "C" THEN c = 143
  4633. IF i$ = "c" OR i$ = "C" THEN GOSUB printnewcolor
  4634. IF i$ = "-" OR i$ = "_" THEN GOSUB printnewcolor
  4635. IF i$ = "f" OR i$ = "F" THEN c = POINT(x + 8, y): IF c = 142 THEN c =
  4636. 143
  4637. IF i$ = "s" OR i$ = "S" THEN GOTO savefromkeyboard
  4638. IF i$ = "l" OR i$ = "L" THEN GOSUB bloadscrn: GOTO cursor
  4639. IF i$ = "u" OR i$ = "U" THEN flag$ = "jump"
  4640. IF flag$ = "" THEN PAINT (x, y), c, 142: PSET (X1, Y1), c
  4641. PUT (x - 3, y - 3), d: FOR d = 0 TO 50: NEXT: PUT (x - 3, y - 3), d
  4642. i$ = "": GOTO inkey3
  4643. keyboardscanfromzoom:
  4644. IF ASC(MID$(i$, 2)) = 75 THEN x = x - 8: X1 = X1 - 1
  4645. IF ASC(MID$(i$, 2)) = 77 THEN x = x + 8: X1 = X1 + 1
  4646. IF ASC(MID$(i$, 2)) = 72 THEN y = y - 8: Y1 = Y1 - 1
  4647. IF ASC(MID$(i$, 2)) = 80 THEN y = y + 8: Y1 = Y1 + 1
  4648. IF ASC(MID$(i$, 2)) = 71 THEN x = x - 8: y = y - 8: X1 = X1 - 1: Y1 =
  4649. Y1 - 1
  4650. IF ASC(MID$(i$, 2)) = 79 THEN x = x - 8: y = y + 8: X1 = X1 - 1: Y1 =
  4651. Y1 + 1
  4652. IF ASC(MID$(i$, 2)) = 73 THEN x = x + 8: y = y - 8: X1 = X1 + 1: Y1 =
  4653. Y1 - 1
  4654. IF ASC(MID$(i$, 2)) = 81 THEN x = x + 8: y = y + 8: X1 = X1 + 1: Y1 =
  4655. Y1 + 1
  4656. IF x > 256 THEN x = 256
  4657. IF x < 104 THEN x = 104
  4658. IF y > 160 THEN y = 160
  4659. IF y < 8 THEN y = 8
  4660. IF X1 < 50 THEN X1 = 50
  4661. IF X1 > 69 THEN X1 = 69
  4662. IF Y1 > 69 THEN Y1 = 69
  4663. IF Y1 < 50 THEN Y1 = 50
  4664. IF flag$ = "jump" THEN GOSUB putcursor: GOTO inkey3
  4665. PAINT (x, y), c, 142
  4666. PSET (X1, Y1), c
  4667. GOTO inkey3
  4668. savefromkeyboard:
  4669. GET (50, 50)-(69, 69), PIX
  4670. DEF SEG = &HA000: BLOAD "temp.bin", 0
  4671. PUT (x%, y%), PIX, PSET
  4672. GOTO cursor
  4673.  
  4674. preparetoexit:
  4675. REM blanks cursor and saves-ends
  4676. PUT (x%, y%), B: PUT (x%, y%), B
  4677. inkey4:
  4678. i$ = INKEY$: IF i$ = "" THEN GOTO inkey4
  4679. IF i$ = "g" OR i$ = "G" THEN CLS : SCREEN 0: END
  4680. GOTO inkey4
  4681. errorroutine:
  4682. SCREEN 0: WIDTH 80: CLS : RESUME restart
  4683. keyboard:
  4684. DIM inregs AS RegTypeX, outregs AS RegTypeX
  4685. filespec$ = "*.cap" + CHR$(0)
  4686. PRINT STRING$(75, 196)
  4687. inregs.ax = &H2F00
  4688. CALL INTERRUPTX(&H21, inregs, outregs)
  4689. data.seg = outregs.es
  4690. data.off = outregs.bx
  4691. inregs.ax = &H4E00
  4692. inregs.dx = SADD(filespec$)
  4693. inregs.ds = -1
  4694. CALL INTERRUPTX(&H21, inregs, outregs)
  4695. cy = outregs.flags AND 1
  4696. IF cy = 0 THEN
  4697. WHILE cy = 0
  4698. DEF SEG = data.seg
  4699. f.name$ = ""
  4700. i = data.off + 30
  4701. WHILE PEEK(i) <> 0
  4702. f.name$ = f.name$ + CHR$(PEEK(i))
  4703. i = i + 1
  4704. WEND
  4705. DEF SEG
  4706. PRINT f.name$ + " ";
  4707. inregs.ax = &H4F00
  4708. CALL INTERRUPTX(&H21, inregs, outregs)
  4709. cy = outregs.flags AND 1
  4710. WEND
  4711. ELSE GOSUB PRINTNOCAPFILES
  4712. END IF
  4713. PRINT STRING$(75, 196)
  4714. INPUT "Filename to load"; n$
  4715. RETURN
  4716. PRINTNOCAPFILES:
  4717. PRINT "There are no .CAP files in this directory."
  4718. PRINT STRING$(75, 196)
  4719. INKEY5:
  4720. i$ = INKEY$: IF i$ = "" THEN GOTO INKEY5
  4721. DEF SEG : CLS : SCREEN 0: WIDTH 80: END
  4722. putcursor:
  4723. PUT (x - 3, y - 3), d
  4724. FOR d = 0 TO 50: NEXT
  4725. PUT (x - 3, y - 3), d
  4726. RETURN
  4727. printnewcolor:
  4728. PAINT (180, 185), c, 142
  4729. LOCATE 25, 30
  4730. PRINT "    ";
  4731. LOCATE 25, 30
  4732. PRINT c;
  4733. RETURN
  4734. bloadscrn:
  4735. CLS
  4736. DEF SEG = &HA000
  4737. BLOAD "temp.bin", 0
  4738. RETURN
  4739.  
  4740. '
  4741.  
  4742. Msg #:  1017                      QUIKBAS Subboard
  4743.  From:  RICH GELDREICH            Sent: 04-09-93 22:54
  4744.    To:  QUINN TYLER JACKSON       Rcvd: -NO-
  4745.    Re:  COMP002C.BAS 1/7
  4746.  
  4747. This is a newer version of the compressor. I've greatly improved the 
  4748. documentation of the program, and fixed a few bugs. The decompressor 
  4749. hasn't changed. 
  4750.  
  4751. '_____O_/________________________| SNIP |______________________\_O___
  4752. '     O \                        | HERE |                      / O
  4753. 'This file created by PostIt! v6.0.
  4754. '>>> Start of page 1.
  4755.  
  4756. '--------------------------------------------------------------------
  4757. 'File name:   COMP002C.BAS
  4758. 'Description: Compresses  variable  length  strings  using  LZ77
  4759. '             based sliding dictionary algorithm.
  4760. 'Revision:    1.1
  4761. 'Compiler:    At least PDS.
  4762. 'Author:      Rich Geldreich
  4763. 'Date:        April 1993
  4764. '
  4765. 'Fixes in revision 1.1:
  4766. '  1. Found stupid bug in SrgSlideDict routine that cause it to not
  4767. '  remove strings that slid out of the dictionary.
  4768. '  2. Added & rewrote comments so people other than me can understand
  4769. '  what the hell this thing is doing. :-)
  4770. '  3. Renamed internal functions so they were prefixed with "Frg"
  4771. '  instead of "Fun" like Quinn wanted.
  4772. '  4. Shrunk hash table to 1024 linked lists so less memory is used
  4773. '  and because it didn't seem to increase speed much with most files.
  4774. '--------------------------------------------------------------------
  4775. 'The LZ77  algorithm  reduces  the  size  required  to  store data by
  4776. 'replacing strings of characters with  pointers  to  previously  sent
  4777. 'strings.   The  algorithm always tries to find a match for a string;
  4778. 'if no match can be found  a  single  character of the string is sent
  4779. 'uncompressed and the search starts over  with  the  next  character.
  4780. 'This  is  done until no more characters remain to be compressed.  In
  4781. 'theory the algorithm is  very  simple, but getting an implementation
  4782. 'of it up to speed is a bit of a challenge.
  4783. '--------------------------------------------------------------------
  4784. 'How this program works:
  4785. '
  4786. 'This program finds matches for upcoming text by organizing thousands
  4787. 'of linked lists which contain strings  which all start with the same
  4788. 'three characters(due to hashing collisions this is not true  all  of
  4789. 'the time, but the searching algorithm ignores these conditions).
  4790. '
  4791. 'For instance, all strings which  start  with  the  characters  "ABC"
  4792. 'would  be in the same linked list, so finding a match for any string
  4793. 'beginning with "ABC" is  a  simple  matter  of searching through the
  4794. '"ABC" list and comparing.  A pointer to the largest match would then
  4795. 'sent to the output stream.  Since the  pointer  would  require  less
  4796. 'space than the string it replaced, compression would occur.
  4797. '--------------------------------------------------------------------
  4798. DEFINT A-Z
  4799. CONST Version = 1
  4800. CONST True = -1, False = 0
  4801.  
  4802. CONST DictSize = 8192
  4803. 'The ZoneSize constant must evenly divide into the DictSize constant!
  4804. CONST ZoneSize = 1024
  4805. CONST MaxTries = 100    'Affects speed vs. compression.
  4806. 'The HashSize constant must be a power of two!
  4807. CONST HashSize = 2048   'Affects speed vs.  memory.
  4808. 'Do not change MinMatch, because the entire program depends on it
  4809. 'being three.
  4810. CONST MinMatch = 3
  4811. CONST MaxMatch = 266
  4812.  
  4813. TYPE BitOutputType
  4814.     ByteOffset  AS INTEGER
  4815.     BitOffset   AS INTEGER
  4816.     BitBuffer   AS LONG
  4817. END TYPE
  4818.  
  4819. ' Sliding Dictionary
  4820. REDIM SHARED Dictionary(0)
  4821.  
  4822. ' Hash table, each element is the head of its own linked list.
  4823. ' Each linked lists contains strings which start with the same three
  4824. ' character sequence.
  4825. REDIM SHARED HashTable(0)
  4826.  
  4827. ' Linked list pointers. Each NextString() array element contains
  4828. either
  4829. ' -1,  which signals that this is the last string in the list, or a
  4830. ' pointer to another string that hashed to the same value and occured
  4831. ' before it in dictionary.
  4832. REDIM SHARED NextString(0)
  4833.  
  4834.  
  4835. DIM SHARED IsInitialized
  4836. DIM SHARED PowerOfTwo(0 TO 15) AS LONG  'For fast shifts
  4837. DIM SHARED OutputString$, OutputInfo AS BitOutputType
  4838. DIM SHARED BytesToCompress, UnCompressable
  4839.  
  4840. FUNCTION FrgCompression (InText$)
  4841.     'Allocate work arrays.
  4842.     REDIM Dictionary(0 TO (DictSize + MaxMatch) - 1)
  4843.     REDIM HashTable(0 TO HashSize - 1)
  4844.     REDIM NextString(0 TO DictSize - 1)
  4845.  
  4846.     SrgLoadHashTable
  4847.  
  4848.     SlidePointer = 0
  4849.     StringPointer = 1
  4850.     BytesLeft = BytesToCompress
  4851.  
  4852.     DO UNTIL UnCompressable OR BytesLeft = 0
  4853.       'Dictionary all filled up?
  4854.         IF SlidePointer = DictSize THEN
  4855.           'Move dictionary "left" ZoneSize characters so more
  4856.           'data can be copied into it.
  4857.             SlidePointer = DictSize - ZoneSize
  4858.             SrgSlideDict
  4859.         END IF
  4860.  
  4861.       'Find how many bytes we can do in this zone.
  4862.         BytesToDo = ZoneSize
  4863.         IF BytesLeft < ZoneSize THEN BytesToDo = BytesLeft
  4864.  
  4865.       'Enter new characters to compress into hash table and
  4866.       'linked lists.
  4867.         SrgHash InText$, SlidePointer, StringPointer, BytesToDo
  4868.  
  4869.       'Compress the data zone.
  4870.         SrgSearch SlidePointer, BytesToDo
  4871.  
  4872.         BytesLeft = BytesLeft - BytesToDo
  4873.         StringPointer = StringPointer + BytesToDo
  4874.         SlidePointer = SlidePointer + ZoneSize
  4875.     LOOP
  4876.  
  4877.   'If data can't be compressed then just store it.
  4878.     IF UnCompressable THEN
  4879.         MID$(OutputString$, 17) = InText$
  4880.         OutputInfo.ByteOffset = 17 + BytesToCompress
  4881.         FrgCompression = 0
  4882.     ELSE
  4883.       'Flush output buffer.
  4884.         SrgWriteBits 0, 7
  4885.         FrgCompression = 1
  4886.     END IF
  4887.  
  4888.   'Deallocate work arrays.
  4889.     REDIM Dictionary(0)
  4890.     REDIM HashTable(0)
  4891.     REDIM NextString(0)
  4892.  
  4893. END FUNCTION
  4894.  
  4895. 'InText$ is the string to compress. The string returned is the
  4896. 'compressed version of InText$. If  ErrorCode  is  not zero,
  4897. 'then expect one of the following error codes:
  4898. '       -1 = String is null.
  4899. '       -2 = String is too large.
  4900. FUNCTION FunGeldComp$ (InText$, ErrorCode)
  4901.     FunGeldComp$ = ""
  4902.     ErrorCode = 0
  4903.  
  4904.   'Initialize power of two table if first time in function.
  4905.     IF IsInitialized = False THEN
  4906.         IsInitialized = True
  4907.  
  4908.         J& = 1
  4909.         FOR a = 0 TO 15
  4910.             PowerOfTwo(a) = J&
  4911.             J& = J& * 2 'SHL 1
  4912.         NEXT
  4913.     END IF
  4914.  
  4915.     BytesToCompress = LEN(InText$)
  4916.  
  4917.     UnCompressable = False
  4918.  
  4919.   'If no characters to compress, then exit. This may change.. ?
  4920.     IF BytesToCompress = 0 THEN
  4921.         ErrorCode = -1
  4922.         EXIT FUNCTION
  4923.  
  4924.   'If more than 32,000 bytes to compress then exit with error
  4925.   'because an out of string space error will probably occur.
  4926.     ELSEIF BytesToCompress > 32000 THEN
  4927.         ErrorCode = -2
  4928.         EXIT FUNCTION
  4929.     END IF
  4930.   'Initialize output string.
  4931.     OutputString$ = SPACE$(128 + BytesToCompress)
  4932.  
  4933.   'Initialize bit output structure.
  4934.     OutputInfo.ByteOffset = 17
  4935.     OutputInfo.BitOffset = 0
  4936.     OutputInfo.BitBuffer = 0
  4937.  
  4938.   'Write string header.
  4939.     MID$(OutputString$, 1) = "REN"                  '1-3
  4940.     MID$(OutputString$, 4) = CHR$(Version)          '4-4
  4941.     MID$(OutputString$, 5) = MKI$(BytesToCompress)  '5-6
  4942.  
  4943.   'Attempt to compress the string.
  4944.     Algorithm = FrgCompression(InText$)
  4945.  
  4946.   'Store number of bytes stored or compressed and algorithm into
  4947.   'string header.
  4948.     MID$(OutputString$, 7) = MKI$(OutputInfo.ByteOffset - 17)'7-8
  4949.     MID$(OutputString$, 9) = CHR$(Algorithm)
  4950.  
  4951.     FunGeldComp$ = LEFT$(OutputString$, OutputInfo.ByteOffset)
  4952.   'Deallocate global work string for efficiency.
  4953.     OutputString$ = ""
  4954.  
  4955.  
  4956. END FUNCTION
  4957.  
  4958. SUB SrgChar (BYVAL Char)
  4959.  
  4960.   'Output one bit as a flag and an unencoded character to the
  4961. ' output
  4962.   'string.
  4963.     SrgWriteBits Char * 2, 9
  4964.  
  4965. END SUB
  4966.  
  4967. SUB SrgHash (InText$, BYVAL SlidePointer, BYVAL StringPointer,_
  4968.  BYVAL TotalBytes)
  4969.  
  4970.   'Copy the new characters from the input string into dictionary.
  4971.     J = SlidePointer
  4972.     FOR a = StringPointer TO StringPointer + TotalBytes - 1
  4973.         Dictionary(J) = ASC(MID$(InText$, a, 1))
  4974.         J = J + 1
  4975.     NEXT
  4976.  
  4977.   'Enter characters into hash table. Each three character sequence in
  4978.   'the dictionary is hashed and placed at the head of the linked list
  4979.   'which contains the strings which start with those same three
  4980.   'characters.
  4981.  
  4982.   'This ensures that each linked list is always sorted by age, where
  4983.   'the oldest strings (the least important strings) are near the end
  4984.   'of the linked list and the youngest strings are near the head of
  4985.   'the list.
  4986.  
  4987.   'After hashing, compressing the data is a simple matter of running
  4988.   'down a string's linked list and comparing to find the largest match.
  4989.  
  4990.   'Initialize the hash accumulator.
  4991.  
  4992.     hash = (Dictionary(SlidePointer) * 32 XOR Dictionary(SlidePointer + 1))
  4993.  
  4994.     FOR a = SlidePointer TO (SlidePointer + TotalBytes - 1) - 2
  4995.       'Shift left hash accumulator five places and XOR it with the next
  4996.       'character.
  4997.  
  4998.       'The accumulator is shifted left five places so only the last
  4999.       'three characters are used in the hash(5*3=15 bits).
  5000.  
  5001.         hash = (((hash AND 1023) * 32) XOR Dictionary(a + 2)) AND (HashSize - 1)
  5002.         J = a
  5003.  
  5004.       'Make the new string the head of its linked list.
  5005.  
  5006.         SWAP HashTable(hash), J 'Make hash table entry point to new string.
  5007.         NextString(a) = J       'Make new string point to old string.
  5008.     NEXT
  5009.  
  5010.   'Set the last two strings which weren't hashed in the above loop
  5011.   'to null, because they are at the end of the zone where there aren't
  5012.   'enough characters to find a match over the two character threshold of
  5013.   'this program. (One thing to note: this algorithm cannot find
  5014.   'matches between zone boundries.)
  5015.  
  5016.     FOR a = (SlidePointer + TotalBytes - 1) - 1 TO (SlidePointer + TotalBytes - 1)
  5017.         'Don't access negative array elements, this may happen when
  5018.         'the amount of characters in the zone is very small.
  5019.         IF a >= 0 THEN NextString(a) = -1
  5020.     NEXT
  5021.  
  5022. END SUB
  5023.  
  5024. SUB SrgLoadHashTable
  5025.  
  5026.   'Initialize all elements in hash table to null.
  5027.     FOR a = 0 ╧ HashSize - 1
  5028.         HashTable(a) = -1
  5029.     NEXT
  5030.  
  5031. END SUB
  5032.  
  5033. SUB SrgMatch (BYVAL MatchPos, BYVAL MatchLen)
  5034.   'This output system could be improved greatly!
  5035.  
  5036.     SrgWriteBits 1, 1
  5037.  
  5038.     a = MatchLen - MinMatch
  5039.  
  5040.     IF a <= 7 THEN
  5041.         SrgWriteBits 0, 1
  5042.         SrgWriteBits a, 3
  5043.     ELSE
  5044.         SrgWriteBits 1, 1
  5045.         a = a - 8
  5046.         IF a <= 31 THEN
  5047.             SrgWriteBits 0, 1
  5048.             SrgWriteBits a, 5
  5049.         ELSE
  5050.             SrgWriteBits 1, 1
  5051.             SrgWriteBits a, 8
  5052.         END IF
  5053.     END IF
  5054.  
  5055.   'Favor closer matches which occur more often than far matches.
  5056.     IF MatchPos <= 511 THEN
  5057.         SrgWriteBits 0, 1
  5058.         SrgWriteBits MatchPos, 9
  5059.     ELSE
  5060.         SrgWriteBits 1, 1
  5061.         SrgWriteBits MatchPos, 13
  5062.     END IF
  5063.  
  5064. END SUB
  5065.  
  5066. SUB SrgScan (BYVAL SlidePos, MatchPos, MatchLen) STATIC
  5067.   'This subroutine finds the longest & closest match in the dictionary
  5068.   'for the string at position SlidePos.
  5069.  
  5070.   'Only the strings which occured before the string at SlidePos are
  5071.   'compared, because the decompressor already has these strings in
  5072.   'its dictionary. Also, only the strings which hash to the same
  5073.   'value are compared against the string at SlidePos. Finding these
  5074.   'strings is very simple because they are always stored in the
  5075.   'same linked list as the string at SlidePos is in.
  5076.  
  5077.   'Mimick a current match length to two characters.
  5078.     MatchLen = 2
  5079.  
  5080.   'To eliminate worthless compares that do not exceed our best
  5081.   'match found so far one character of the compare string is  tested
  5082.   'against our search string. This character's position is based
  5083.   'on the best match length found so far. If this character matches,
  5084.   'a normal string compare is performed. If it doesn't, the compare is
  5085.   'skipped because the compare string could not possibly match our
  5086.   'search string enough to exceed the best match found so far. This
  5087.   'greatly speeds up the search for the best match because it
  5088.   'eliminates many string compares.
  5089.  
  5090.     MatchChar = Dictionary(SlidePos + MatchLen)
  5091.  
  5092.     'Access linked list to find closest string which hashed to the
  5093.     'same value.
  5094.     ComparePos = NextString(SlidePos)
  5095.  
  5096.     FOR a = 1 TO MaxTries
  5097.         'Have we hit the end of the list?
  5098.         IF ComparePos = -1 THEN EXIT FOR
  5099.  
  5100.       'Only do the compare if the string can exceed our best match
  5101.       'length so far. This saves time because it eliminates futile
  5102.       'compares.
  5103.         IF Dictionary(ComparePos + MatchLen) = MatchChar THEN
  5104.  
  5105.           'Compare the two strings.
  5106.             FOR CompareLen = 0 TO MaxMatch - 1
  5107.                 IF Dictionary(ComparePos + CompareLen) <> Dictionary(SlidePos + CompareLen) THEN EXIT FOR
  5108.             NEXT
  5109.  
  5110.           'If match is larger than current match then make it our
  5111.           'current match.
  5112.             IF CompareLen > MatchLen THEN
  5113.                 MatchLen = CompareLen
  5114.                 MatchPos = ComparePos
  5115.               'If match length = maximum match length then stop
  5116.               'searching because we cannot find any match which
  5117.               'is larger.
  5118.                 IF MatchLen = MaxMatch THEN EXIT SUB
  5119.  
  5120.               'Get new must match character because the match length
  5121.               'was changed.
  5122.                 MatchChar = Dictionary(SlidePos + MatchLen)
  5123.             END IF
  5124.  
  5125.         END IF
  5126.  
  5127.         'Fetch next string which hashed to the same value.
  5128.         ComparePos = NextString(ComparePos)
  5129.     NEXT
  5130.  
  5131.     'If match length didn't change from what it was set to at the
  5132.     'beginning of the search, then set it equal to one character.
  5133.     'This is used as a flag to indicate that no match could be
  5134.     'found for the search string.
  5135.  
  5136.     MatchLen = MatchLen + (MatchLen = 2)
  5137.  
  5138. END SUB
  5139.  
  5140. SUB SrgSearch (BYVAL SlidePointer, BYVAL TotalBytes)
  5141.   'This subroutine replaces upcoming data with pointers to
  5142.   'previously sent data.
  5143.     DO UNTIL TotalBytes = 0 OR UnCompressable
  5144.         SrgScan SlidePointer, MatchPos1, MatchLen1
  5145.  
  5146.       'Add this code to increase compression, but decrease speed:
  5147.  
  5148.         IF (MatchLen1 >= MinMatch) AND (MatchLen1 < 64) THEN
  5149.          'Check match one character ahead and eliminate current
  5150.          'match if it is larger.
  5151.             SrgScan SlidePointer + 1, MatchPos2, MatchLen2
  5152.             IF MatchLen2 > MatchLen1 THEN
  5153.                 SrgChar Dictionary(SlidePointer)
  5154.                 SlidePointer = SlidePointer + 1
  5155.                 TotalBytes = TotalBytes - 1
  5156.                 IF TotalBytes = 0 THEN EXIT DO
  5157.                 MatchLen1 = MatchLen2
  5158.                 MatchPos1 = MatchPos2
  5159.             END IF
  5160.         END IF
  5161.  
  5162.       'If no match found or not enough characters left in zone
  5163.       'for a match then just output one character.
  5164.         IF (MatchLen1 < MinMatch) OR (TotalBytes < MinMatch) THEN
  5165.             SrgChar Dictionary(SlidePointer)
  5166.         ELSE
  5167.           'Limit match length if too long.
  5168.             IF MatchLen1 > TotalBytes THEN MatchLen1 = TotalBytes
  5169.           'Send match pointer and length to output string.
  5170.             SrgMatch SlidePointer - MatchPos1, MatchLen1
  5171.         END IF
  5172.  
  5173.         TotalBytes = TotalBytes - MatchLen1
  5174.         SlidePointer = SlidePointer + MatchLen1
  5175.     LOOP
  5176.  
  5177. END SUB
  5178.  
  5179. 'This subroutine slides the dictionary left ZoneSize characters and
  5180. 'updates the hash table and linked lists.
  5181. SUB SrgSlideDict
  5182.  
  5183.  'Slide dictionary.
  5184.     FOR a = ZoneSize TO DictSize - 1
  5185.         Dictionary(a - ZoneSize) = Dictionary(a)
  5186.     NEXT
  5187.  
  5188.  'Slide linked list cells. Set any cell which points to a string
  5189.  'just slid out of dictionary to -1.
  5190.     FOR a = ZoneSize TO DictSize - 1
  5191.         B = NextString(a) - ZoneSize
  5192.      'If B < 0, then set cell to -1, or null because it points to a
  5193.      'deleted string which just slide out.
  5194.         NextString(a - ZoneSize) = B OR (B < 0)
  5195.     NEXT
  5196.  
  5197.  'Update hash table so it points to the correct strings.
  5198.     FOR a = 0 TO HashSize - 1
  5199.         B = HashTable(a) - ZoneSize
  5200.         HashTable(a) = B OR (B < 0)
  5201.     NEXT
  5202.  
  5203. END SUB
  5204.  
  5205. SUB SrgWriteBits (BYVAL bits, BYVAL NumBits)
  5206.   'This subroutine writes variable length codes to the output
  5207.   'string.
  5208.  
  5209.   'Add bits to bit buffer.
  5210.     OutputInfo.BitBuffer = OutputInfo.BitBuffer OR (bits *_
  5211.  PowerOfTwo(OutputInfo.BitOffset))
  5212.  
  5213.   'NumBits more bits in buffer now.
  5214.     OutputInfo.BitOffset = OutputInfo.BitOffset + NumBits
  5215.  
  5216.   'At least one byte in bit buffer?
  5217.     DO WHILE OutputInfo.BitOffset > 7
  5218.  
  5219.       'Write byte to output string.
  5220.         MID$(OutputString$, OutputInfo.ByteOffset, 1) =_
  5221.  CHR$(OutputInfo.BitBuffer AND 255)
  5222.         OutputInfo.ByteOffset = OutputInfo.ByteOffset + 1
  5223.  
  5224.       'Get rid of byte just  written  by shifting the buffer right 8
  5225.       'times.
  5226.         OutputInfo.BitBuffer = OutputInfo.BitBuffer \ 256 'SHR 8
  5227.  
  5228.       '8 less bits now.
  5229.         OutputInfo.BitOffset = OutputInfo.BitOffset - 8
  5230.  
  5231.       'Check to see if the output position passed the original
  5232.       'string's size.
  5233.         IF OutputInfo.ByteOffset >= (BytesToCompress - 16) THEN
  5234.             UnCompressable = True '!Stop compressing string.
  5235.             EXIT SUB
  5236.         END IF
  5237.     LOOP
  5238.  
  5239. END SUB
  5240.  
  5241.  
  5242. '    That's it! I really feel very embarrased about posting the first
  5243. 'version, because I didn't spend too much time on the remarks, spelling,
  5244. 'and grammer. Maby I jumped the gun and posted it too early.
  5245. '
  5246. '    The next revision will contain a much better coding system for
  5247. 'greater compression and will implement the special handling of different
  5248. 'types of data. It will also use a recursive searching algorithm that
  5249. 'will increase compression on text by 5% or so.
  5250. '
  5251. '
  5252.  
  5253. Msg #:  1073                      QUIKBAS Subboard
  5254.  From:  QUINN TYLER JACKSON       Sent: 04-10-93 00:00
  5255.    To:  RICH GELDREICH            Rcvd: -NO-
  5256.    Re:  COMP002T.BAS
  5257.  
  5258. RICH
  5259.  
  5260. This testing routine has been modified to fit the revised calling syntax
  5261. of the compression function.
  5262.  
  5263. DEFINT A-Z
  5264. DECLARE FUNCTION funGeldComp$ (InText$, TextType, OptimizeType,ErrorCode%)
  5265. DECLARE FUNCTION funGeldDecomp$ (InString$, ErrorCode%)
  5266.  
  5267. CLS
  5268. RANDOMIZE TIMER
  5269.  
  5270. A$ = "c:\dos\wp\fic\" + DIR$("c:\dos\wp\fic\*.txt")
  5271. DO UNTIL A$ = ""
  5272.  
  5273.     K = 10000
  5274.     'K = RND * 10000 + 10
  5275.  
  5276.     OPEN A$ FOR BINARY AS #1
  5277.     IF LOF(1) < K THEN K = LOF(1)
  5278.  
  5279.     UnCompressed$ = SPACE$(K)
  5280.     GET #1, , UnCompressed$
  5281.     CLOSE #1
  5282.  
  5283.     IF LEN(UnCompressed$) = 0 THEN
  5284.         PRINT "Null"
  5285.     ELSE
  5286.         PRINT "C "; LEN(UnCompressed$); "bytes... ";
  5287.         Start! = TIMER
  5288.         TextType = 1 'Text
  5289.         OptType = 1 ' For size
  5290.  
  5291.         Compressed$ = funGeldComp$(UnCompressed$, TextType, OptType, ErrorCode)
  5292.         PRINT LEN(Compressed$); TIMER - Start!;
  5293.         IF ErrorCode THEN
  5294.             PRINT ErrorCode
  5295.             END
  5296.         END IF
  5297.  
  5298.         PRINT "D ";
  5299.         Start! = TIMER
  5300.         Decompressed$ = funGeldDecomp$(Compressed$, ErrorCode)
  5301.         PRINT TIMER - Start!
  5302.         IF ErrorCode THEN
  5303.             PRINT ErrorCode
  5304.             END
  5305.         END IF
  5306.  
  5307.             IF Decompressed$ <> UnCompressed$ THEN STOP
  5308.         END IF
  5309.         PRINT
  5310.  
  5311.         UnCompressed$ = ""
  5312.         Compressed$ = ""
  5313.         Decompressed$ = ""
  5314.  
  5315.  
  5316.     A$ = "c:\dos\wp\fic\" + DIR$
  5317.  
  5318.     IF INKEY$ <> "" THEN END
  5319.  
  5320. LOOP
  5321.  
  5322. DECLARE FUNCTION FunQompress$ (St$)
  5323. DECLARE FUNCTION funGeldComp$ (InText$, TextType%, OptimizeType%, ErrorCode%)
  5324. DECLARE SUB srgChar (BYVAL Char%)
  5325. DECLARE SUB srgHash (InText$, BYVAL SlidePointer%, BYVAL StringPointer%, BYVAL TotalBytes%)
  5326. DECLARE SUB srgLoadHashTable ()
  5327. DECLARE SUB srgMatch (BYVAL MatchPos%, BYVAL MatchLen%)
  5328. DECLARE SUB srgScan (BYVAL SlidePos%, MatchPos%, MatchLen%)
  5329. DECLARE SUB srgSearch (BYVAL SlidePointer%, BYVAL TotalBytes%)
  5330. DECLARE SUB srgSlideDict ()
  5331. DECLARE SUB srgWriteBits (BYVAL Bits%, BYVAL NumBits%)
  5332. DECLARE FUNCTION frgCompression% (InText$)
  5333.  
  5334. '[Comments taken out for this working revision to conserve badwidth.]
  5335.  
  5336. DEFINT A-Z
  5337. CONST VERSION = 1
  5338. CONST TRUE = -1
  5339. FALSE = NOT TRUE
  5340.  
  5341. CONST DictSize = 8192
  5342. 'The ZoneSize constant must evenly divide into the DictSize constant!
  5343. CONST ZoneSize = 2048
  5344.  
  5345. 'Do not change MinMatch, because the entire program depends on it
  5346. 'being three.
  5347. CONST MinMatch = 3
  5348. CONST MaxMatch = 266
  5349.  
  5350. TYPE BitOutputType
  5351.     ByteOffset  AS INTEGER
  5352.     BitOffset   AS INTEGER
  5353.     BitBuffer   AS LONG
  5354. END TYPE
  5355.  
  5356.  
  5357. ' Error constants
  5358. ' These added by QTJ for clarity
  5359.  
  5360. CONST ErrRGCNoInString = -1
  5361. CONST ErrRGCLongInString = -2
  5362. CONST ErrRGCBadHeader = -3
  5363. CONST ErrRGCBadStrLength = -4
  5364. CONST ErrRGCBadAlgoritmFlag = -5
  5365. CONST ErrRGCBadVersion = -6
  5366.  
  5367. ' Sliding Dictionary
  5368. REDIM SHARED Dictionary(0)
  5369.  
  5370. ' Hash table, each element is the "head" of its own linked list.
  5371. ' Each linked lists contains strings which start with the same three
  5372. ' character sequence. (Hashing collisions of course prevent this from
  5373. ' being true all of the time.)
  5374. REDIM SHARED HashTable(0)
  5375.  
  5376. ' Linked list pointers. Each element points to another element before
  5377. ' it in the dictionary, or contains -1 which signals the end of the
  5378. ' linked
  5379. ' list. To search for a match for any element in the dictionary, simply
  5380. ' look up its next string and compare it. Keep on doing this until
  5381. ' we find the largest match, the end of the linked list, or until we
  5382. ' exaust our allowed number of searches (defined by the constant
  5383. ' MaxTries).
  5384. REDIM SHARED NextString(0)
  5385.  
  5386. DIM SHARED IsInitialized
  5387. DIM SHARED PowerOfTwo(0 TO 15) AS LONG
  5388. DIM SHARED OutputString$, OutputInfo AS BitOutputType
  5389. DIM SHARED BytesToCompress, UnCompressable
  5390. DIM SHARED MaxTries
  5391. DIM SHARED HashSize
  5392. DIM SHARED OptType
  5393.  
  5394. FUNCTION frgCompression (InText$)
  5395.  
  5396.     REDIM Dictionary(0 TO (DictSize + MaxMatch) - 1)
  5397.     REDIM HashTable(0 TO HashSize - 1)
  5398.     REDIM NextString(0 TO DictSize - 1)
  5399.  
  5400.     FOR A = 0 TO HashSize - 1
  5401.         HashTable(A) = -1
  5402.     NEXT
  5403.  
  5404.     SlidePointer = 0
  5405.     StringPointer = 1
  5406.     BytesLeft = BytesToCompress
  5407.  
  5408.     DO UNTIL UnCompressable OR BytesLeft = 0
  5409.         'Dictionary all filled up?
  5410.         IF SlidePointer = DictSize THEN
  5411.             SlidePointer = DictSize - ZoneSize
  5412.             'Move dictionary "left" so more characters can be
  5413.             'thrown into it.
  5414.             srgSlideDict
  5415.         END IF
  5416.  
  5417.         'Find how many bytes we can do in this zone...
  5418.         BytesToDo = ZoneSize
  5419.         IF BytesLeft < ZoneSize THEN
  5420.             BytesToDo = BytesLeft
  5421.         END IF
  5422.  
  5423.         'Enter new characters to compress into search structures.
  5424.         srgHash InText$, SlidePointer, StringPointer, BytesToDo
  5425.  
  5426.         'Find matches for the characters.
  5427.         srgSearch SlidePointer, BytesToDo
  5428.  
  5429.         BytesLeft = BytesLeft - BytesToDo
  5430.         StringPointer = StringPointer + BytesToDo
  5431.         SlidePointer = SlidePointer + ZoneSize
  5432.     LOOP
  5433.  
  5434.     'If data can't be compressed then just store it.
  5435.     IF UnCompressable THEN
  5436.         MID$(OutputString$, 17) = InText$
  5437.         OutputInfo.ByteOffset = 17 + BytesToCompress
  5438.         frgCompression = 0
  5439.     ELSE
  5440.         'Flush output buffer.
  5441.         srgWriteBits 0, 8
  5442.         frgCompression = 1
  5443.     END IF
  5444.  
  5445.     'REDIM Dictionary(0)
  5446.     'REDIM HashTable(0)
  5447.     'REDIM NextString(0)
  5448.  
  5449. END FUNCTION
  5450.  
  5451. FUNCTION funGeldComp$ (InText$, TextType, OptimizeType, ErrorCode)
  5452.  
  5453.     OptType = OptimizeType
  5454.     IF TextType = 0 THEN
  5455.         TextType = 1
  5456.     END IF
  5457.     funGeldComp$ = ""
  5458.     ErrorCode = ErrRGCNoError
  5459.  
  5460.  
  5461.     IF NOT IsInitialized THEN
  5462.         IsInitialized = TRUE
  5463.         J& = 1
  5464.         FOR A = 0 TO 15
  5465.             PowerOfTwo(A) = J&
  5466.             J& = J& * 2
  5467.         NEXT
  5468.     END IF
  5469.  
  5470.     BytesToCompress = LEN(InText$)
  5471.     UnCompressable = FALSE
  5472.  
  5473.     SELECT CASE BytesToCompress
  5474.         CASE 0
  5475.             ErrorCode = ErrRGCNoInString
  5476.             EXIT FUNCTION
  5477.         CASE IS > 32000
  5478.             ErrorCode = ErrRGCLongInString
  5479.             EXIT FUNCTION
  5480.     END SELECT
  5481.  
  5482.     ' This table added by QTJ to meet COMP002.ASN specs regarding
  5483.     ' optimization and TextType parameters.  These are only a few of
  5484.     ' the possible variables that can be tweaked to alter algorithm's
  5485.     ' performance according to text and optimizaton types.  The best part
  5486.     ' of this method is that the same decmopression algorithm works for
  5487.     ' all variations.  Some distinctions are really quite minimal, but
  5488.     ' I plan on tweaking this further, later.
  5489.  
  5490.     SELECT CASE TextType + (10 * OptimizeType)
  5491.         CASE 1  ' Text for speed
  5492.             MaxTries = 1
  5493.             HashSize = 2048 * 2
  5494.         CASE 2  ' Foreign for speed
  5495.             MaxTries = 1
  5496.             HashSize = 2048
  5497.         CASE 3  ' Random for speed
  5498.             MaxTries = 1
  5499.             HashSize = 2048
  5500.         CASE 11 ' Text for size
  5501.             MaxTries = 1000
  5502.             HashSize = 2048 * 4
  5503.         CASE 12 ' Foreign for size
  5504.             MaxTries = 1000
  5505.             HashSize = 2048
  5506.         CASE 13 ' Random for size
  5507.             MaxTries = 100
  5508.             HashSize = 2048 * 4
  5509.     END SELECT
  5510.  
  5511.     OutputString$ = SPACE$(128 + BytesToCompress)
  5512.     OutputInfo.ByteOffset = 17
  5513.     OutputInfo.BitOffset = 0
  5514.     OutputInfo.BitBuffer = 0
  5515.  
  5516.     MID$(OutputString$, 1) = "RGC"                  '1-3
  5517.     MID$(OutputString$, 4) = CHR$(VERSION)          '4-4
  5518.     MID$(OutputString$, 5) = MKI$(BytesToCompress)  '5-6
  5519.  
  5520.     Algorithm = frgCompression(InText$)
  5521.  
  5522.     MID$(OutputString$, 7) = MKI$(OutputInfo.ByteOffset - 17)'7-8
  5523.     MID$(OutputString$, 9) = CHR$(Algorithm)
  5524.  
  5525.     funGeldComp$ = LEFT$(OutputString$, OutputInfo.ByteOffset)
  5526.     OutputString$ = ""
  5527.  
  5528. END FUNCTION
  5529.  
  5530. SUB srgHash (InText$, BYVAL SlidePointer, BYVAL StringPointer, BYVAL TotalBytes)
  5531.     'Copy characters from input string into dictionary.
  5532.     J = SlidePointer
  5533.     FOR A = StringPointer TO StringPointer + TotalBytes - 1
  5534.         Dictionary(J) = ASC(MID$(InText$, A, 1))
  5535.         J = J + 1
  5536.     NEXT
  5537.  
  5538.     'Enter characters into hash table. Each three character sequence in
  5539.     'the dictionary is hashed and placed at the head of its linked list.
  5540.     'This ensures that each linked list is always sorted by
  5541.     'age, where the oldest strings (the least important strings) are near
  5542.     'the end of the linked list and the youngest strings are near the
  5543.     'head of the list. After hashing, compressing the data is a simple
  5544.     'matter of running down a string's linked list and comparing to find
  5545.     'the largest match.
  5546.  
  5547.     'Initialize the hash accumulator.
  5548.     Hash = (Dictionary(SlidePointer) * 32 XOR Dictionary(SlidePointer + 1))
  5549.  
  5550.     FOR A = SlidePointer TO (SlidePointer + TotalBytes - 1) - 2
  5551.         'Shift left hash accumulator 5 places and XOR it with
  5552.         'the next character.
  5553.         Hash = (((Hash AND 1023) * 32) XOR Dictionary(A + 2)) AND (HashSize - 1)
  5554.         J = A
  5555.  
  5556.         'Make the new string the "head" of its linked list.
  5557.  
  5558.         'Make hash table entry point to new string.
  5559.         SWAP HashTable(Hash), J
  5560.         'Make new string point to old string.
  5561.         NextString(A) = J
  5562.     NEXT
  5563.  
  5564.     'Set the last two strings which weren't hashed in the above loop
  5565.     'to -1.
  5566.     FOR A = (SlidePointer + TotalBytes - 1) - 1 TO (SlidePointer + TotalBytes - 1)
  5567.         IF A >= 0 THEN
  5568.             NextString(A) = -1
  5569.         END IF
  5570.     NEXT
  5571.  
  5572. END SUB
  5573.  
  5574. SUB srgMatch (BYVAL MatchPos, BYVAL MatchLen)
  5575.  
  5576.     'This output system could be improved greatly!
  5577.  
  5578.     srgWriteBits 1, 1
  5579.  
  5580.     A = MatchLen - MinMatch
  5581.         srgWriteBits MatchPos, 9
  5582.     ELSE
  5583.         srgWriteBits 1, 1
  5584.         srgWriteBits MatchPos, 13
  5585.     END IF
  5586. END SUB
  5587.  
  5588. SUB srgScan (BYVAL SlidePos, MatchPos, MatchLen)
  5589. ' THIS IS TO BE WRITTEN IN MASM!
  5590.  
  5591.     'This subroutine finds a match for the string at position SlidePos.
  5592.  
  5593.     MatchLen = 2
  5594.  
  5595.     MatchChar = Dictionary(SlidePos + MatchLen)
  5596.  
  5597.     ComparePos = NextString(SlidePos)
  5598.  
  5599.     FOR A = 1 TO MaxTries
  5600.         IF ComparePos = -1 THEN
  5601.             EXIT FOR
  5602.         END IF
  5603.         'Only do the compare if the character at the current match length
  5604.         'matches.
  5605.         IF Dictionary(ComparePos + MatchLen) = MatchChar THEN
  5606.  
  5607.             FOR SearchLen = 0 TO MaxMatch - 1
  5608.                 IF Dictionary(ComparePos + SearchLen) <> Dictionary(SlidePos + SearchLen) THEN
  5609.                     EXIT FOR
  5610.                 END IF
  5611.             NEXT
  5612.  
  5613.             IF SearchLen > MatchLen THEN
  5614.                 MatchLen = SearchLen
  5615.                 MatchPos = ComparePos
  5616.                 IF MatchLen = MaxMatch THEN
  5617.                     EXIT SUB
  5618.                 END IF
  5619.                 MatchChar = Dictionary(SlidePos + MatchLen)
  5620.             END IF
  5621.         END IF
  5622.  
  5623.         ComparePos = NextString(ComparePos)
  5624.     NEXT
  5625.  
  5626.     MatchLen = MatchLen + (MatchLen = 2)
  5627.  
  5628. END SUB
  5629.  
  5630. SUB srgSearch (BYVAL SlidePointer, BYVAL TotalBytes)
  5631.  
  5632.     DO UNTIL TotalBytes = 0 OR UnCompressable
  5633.         srgScan SlidePointer, MatchPos1, MatchLen1
  5634.  
  5635.         IF OptType THEN ' optimize for size at the cost of speed
  5636.                 IF (MatchLen1 >= MinMatch) AND (MatchLen1 < 64) THEN
  5637.                     srgScan SlidePointer + 1, MatchPos2, MatchLen2
  5638.                     IF MatchLen2 > MatchLen1 THEN
  5639.                         srgWriteBits Dictionary(SlidePointer) * 2, 9
  5640.                         SlidePointer = SlidePointer + 1
  5641.                         TotalBytes = TotalBytes - 1
  5642.                         IF TotalBytes = 0 THEN
  5643.                             EXIT DO
  5644.                         END IF
  5645.                         MatchLen1 = MatchLen2
  5646.                         MatchPos1 = MatchPos2
  5647.                     END IF
  5648.                 END IF
  5649.        END IF
  5650.  
  5651.         IF (MatchLen1 < MinMatch) OR (TotalBytes < MinMatch) THEN
  5652.             srgWriteBits Dictionary(SlidePointer) * 2, 9
  5653.         ELSE
  5654.             IF MatchLen1 > TotalBytes THEN
  5655.                 MatchLen1 = TotalBytes
  5656.             END IF
  5657.             srgMatch SlidePointer - MatchPos1, MatchLen1
  5658.         END IF
  5659.  
  5660.         TotalBytes = TotalBytes - MatchLen1
  5661.         SlidePointer = SlidePointer + MatchLen1
  5662.     LOOP
  5663.  
  5664. END SUB
  5665.  
  5666. 'This subroutine slides the dictionary down ZoneSize characters and
  5667. 'updates the hash table and linked lists.
  5668. SUB srgSlideDict ()
  5669.  
  5670.     'Slide dictionary.
  5671.     FOR A = ZoneSize TO DictSize - 1
  5672.         Dictionary(A - ZoneSize) = Dictionary(A)
  5673.     NEXT
  5674.  
  5675.     'Slide linked list cells. Set any cell which points to a string
  5676.     'just slid out to -1.
  5677.  
  5678.     FOR A = ZoneSize TO DictSize - 1
  5679.         B = NextString(A) - ZoneSize
  5680.         'If B < 0, then set cell to -1, or null.
  5681.         NextString(A - ZoneSize) = B OR (B < 0)
  5682.     NEXT
  5683.  
  5684.     'Update hash table so it points to the correct strings.
  5685.     FOR A = 0 TO HashSize - 1
  5686.         B = HashTable(A) - ZoneSize
  5687.         HashTable(A) = B OR (B < 0)
  5688.     NEXT
  5689.  
  5690. END SUB
  5691.  
  5692. SUB srgWriteBits (BYVAL Bits, BYVAL NumBits)
  5693. 'THIS IS TO BE WRITTEN IN MASM!
  5694.  
  5695.     OutputInfo.BitBuffer = OutputInfo.BitBuffer OR (Bits * PowerOfTwo(OutputInfo.BitOffset))
  5696.  
  5697.     OutputInfo.BitOffset = OutputInfo.BitOffset + NumBits
  5698.  
  5699.     DO WHILE OutputInfo.BitOffset > 7
  5700.         MID$(OutputString$, OutputInfo.ByteOffset, 1) = CHR$(OutputInfo.BitBuffer AND 255)
  5701.         OutputInfo.ByteOffset = OutputInfo.ByteOffset + 1
  5702.  
  5703.         OutputInfo.BitBuffer = OutputInfo.BitBuffer \ 256 'SHR 8
  5704.         OutputInfo.BitOffset = OutputInfo.BitOffset - 8
  5705.  
  5706.         IF OutputInfo.ByteOffset >= (BytesToCompress - 16) THEN
  5707.             UnCompressable = TRUE
  5708.             EXIT SUB
  5709.        END IF
  5710.     LOOP
  5711.  
  5712. END SUB
  5713.  
  5714.  
  5715.  From:  QUINN TYLER JACKSON       Sent: 04-09-93 23:59
  5716.    To:  RICH GELDREICH            Rcvd: -NO-
  5717.    Re:  COMP002D.BAS          1/
  5718.  
  5719.  
  5720. ' COMP002D.BAS Written by Rich Geldreich for QBCIMR BBS Project
  5721. ' Tweaked by Quinn Tyler Jackson for speed and size.
  5722.  
  5723. DECLARE FUNCTION funGeldDecomp$ (InString$, ErrorCode%)
  5724. DECLARE FUNCTION frgGetBit% (InString$)
  5725. DECLARE FUNCTION frgGetBits% (BYVAL NumBits%, InString$)
  5726. DECLARE FUNCTION frgGetMatchLen% (InString$)
  5727. DECLARE FUNCTION frgGetMatchPos% (InString$)
  5728.  
  5729. DEFINT A-Z
  5730.  
  5731. CONST VERSION = 1
  5732. CONST TRUE = -1
  5733. FALSE = 0
  5734.  
  5735. CONST DictSize = 8192
  5736. CONST MinMatch = 3
  5737.  
  5738. ' Error constants added by QTJ for clarity
  5739. CONST ErrRGCNoInString = -1
  5740. CONST ErrRGCLongInString = -2
  5741. CONST ErrRGCBadHeader = -3
  5742. CONST ErrRGCBadStrLength = -4
  5743. CONST ErrRGCBadAlgoritmFlag = -5
  5744. CONST ErrRGCBadVersion = -6
  5745.  
  5746. TYPE BitInputType
  5747.     ByteOffset  AS INTEGER
  5748.     BitOffset   AS INTEGER
  5749.     BitBuffer   AS LONG
  5750. END TYPE
  5751.  
  5752. DIM SHARED IsInitialized
  5753. DIM SHARED PowerOfTwo(0 TO 15) AS LONG
  5754. DIM SHARED InputInfo AS BitInputType
  5755.  
  5756. FUNCTION frgGetBit (InString$)
  5757. ' THIS IS TO BE WRITTEN IN MASM!
  5758.  
  5759.     IF InputInfo.BitOffset = 0 THEN
  5760.         InputInfo.BitBuffer = ASC(MID$(InString$,InputInfo.ByteOffset, 1))
  5761.         InputInfo.ByteOffset = InputInfo.ByteOffset + 1
  5762.         InputInfo.BitOffset = 8
  5763.     END IF
  5764.  
  5765.     frgGetBit = InputInfo.BitBuffer AND 1
  5766.     InputInfo.BitBuffer = InputInfo.BitBuffer \ 2
  5767.     InputInfo.BitOffset = InputInfo.BitOffset - 1
  5768.  
  5769. END FUNCTION
  5770.  
  5771. FUNCTION frgGetBits (BYVAL NumBits, InString$)
  5772. ' THIS IS TO BE WRITTEN IN MASM!
  5773.  
  5774.     DO WHILE NumBits > InputInfo.BitOffset
  5775.         InputInfo.BitBuffer = InputInfo.BitBuffer OR ASC(MID$(InString$, InputInfo.ByteOffset, 1)) * PowerOfTwo(InputInfo.BitOffset)
  5776.         InputInfo.ByteOffset = InputInfo.ByteOffset + 1
  5777.         InputInfo.BitOffset = InputInfo.BitOffset + 8
  5778.     LOOP
  5779.  
  5780.     K = PowerOfTwo(NumBits)
  5781.  
  5782.     frgGetBits = InputInfo.BitBuffer AND (K - 1)
  5783.     InputInfo.BitBuffer = InputInfo.BitBuffer \ K
  5784.     InputInfo.BitOffset = InputInfo.BitOffset - NumBits
  5785.  
  5786. END FUNCTION
  5787.  
  5788. FUNCTION funGeldDecomp$ (InString$, ErrorCode)
  5789.  
  5790.     funGeldDecomp$ = ""
  5791.     ErrorCode = ErrRGCNoError
  5792.  
  5793.     IF LEN(InString$) <= 16 OR LEFT$(InString$, 3) <> "RGC" THEN
  5794.         ErrorCode = ErrRGCBadHeader
  5795.         EXIT FUNCTION
  5796.     ELSE
  5797.         ' This is a version compatability table.  As versions progress,
  5798.         ' those that are compatible will be added to the first case.
  5799.         ' All other versions will exit with an ErrRGCBadVersion error.
  5800.         ' This allows for revisions that maintain compatibility with strings
  5801.         ' compressed by previous versions, while also catching those strings
  5802.         ' that are no longer compatible with the decompressor.  Added by
  5803.         ' QTJ.
  5804.         SELECT CASE ASC(MID$(InString$, 4, 2))
  5805.             CASE 1 ' All compatible revision numbers added here
  5806.                 ' Do nothing!
  5807.             CASE ELSE ' This covers non-compatible revisions as time passes
  5808.                 ErrorCode = ErrRGCBadVersionNum
  5809.                 EXIT FUNCTION
  5810.         END SELECT
  5811.     END IF
  5812.  
  5813.     IF NOT IsInitialized THEN
  5814.         IsInitialized = TRUE
  5815.  
  5816.         J& = 1
  5817.         FOR A = 0 TO 15
  5818.             PowerOfTwo(A) = J&
  5819.             J& = J& * 2
  5820.         NEXT
  5821.  
  5822.     END IF
  5823.  
  5824.     BytesToDecompress = CVI(MID$(InString$, 5, 2))
  5825.     BytesCompressed = CVI(MID$(InString$, 7, 2))
  5826.     Algorithm = ASC(MID$(InString$, 9, 1))
  5827.  
  5828.     IF (LEN(InString$) - 16) < BytesCompressed THEN
  5829.         ErrorCode = ErrRGCBadStrLength
  5830.         EXIT FUNCTION
  5831.     END IF
  5832.  
  5833.     SELECT CASE Algorithm
  5834.     CASE 0
  5835.         funGeldDecomp$ = MID$(InString$, 17, BytesToDecompress)
  5836.     CASE 1
  5837.         OutputString$ = SPACE$(BytesToDecompress)
  5838.  
  5839.         OutputOffset = 1
  5840.  
  5841.         InputInfo.ByteOffset = 17
  5842.         InputInfo.BitBuffer = 0
  5843.         InputInfo.BitOffset = 0
  5844.  
  5845.         DO UNTIL OutputOffset > BytesToDecompress
  5846.             IF frgGetBit(InString$) THEN
  5847.                 ' Brought in-line to reduce calling overhead: QTJ
  5848.                 IF frgGetBit(InString$) THEN
  5849.                     IF frgGetBit(InString$) THEN
  5850.                         MatchLen = MinMatch + 8 + frgGetBits(8, InString$)
  5851.                     ELSE
  5852.                         MatchLen = MinMatch + 8 + frgGetBits(5, InString$)
  5853.                     END IF
  5854.                 ELSE
  5855.                     MatchLen = MinMatch + frgGetBits(3, InString$)
  5856.                 END IF
  5857.  
  5858.                 ' Brought in-line to reduce calling overhead: QTJ
  5859.                 IF frgGetBit(InString$) THEN
  5860.                     MatchPos = frgGetBits(13, InString$)
  5861.                 ELSE
  5862.                     MatchPos = frgGetBits(9, InString$)
  5863.                 END IF
  5864.  
  5865.                 IF MatchPos <= MatchLen THEN
  5866.                     MatchPos = OutputOffset - MatchPos
  5867.                     FOR J = 0 TO MatchLen - 1
  5868.                         MID$(OutputString$, OutputOffset + J) = MID$(OutputString$, MatchPos + J, 1)
  5869.                     NEXT
  5870.                 ELSE
  5871.                     MatchPos = OutputOffset - MatchPos
  5872.                     MID$(OutputString$, OutputOffset) = MID$(OutputString$, MatchPos, MatchLen)
  5873.                 END IF
  5874.  
  5875.                 OutputOffset = OutputOffset + MatchLen
  5876.             ELSE
  5877.                 MID$(OutputString$, OutputOffset) = CHR$(frgGetBits(8, InString$))
  5878.                 OutputOffset = OutputOffset + 1
  5879.             END IF
  5880.         LOOP
  5881.  
  5882.         IF OutputOffset <> (BytesToDecompress + 1) THEN
  5883.             ErrorCode = ErrRGCBadStrLength
  5884.         ELSE
  5885.             funGeldDecomp$ = OutputString$
  5886.         END IF
  5887.  
  5888.         OutputString$ = ""
  5889.  
  5890.     CASE ELSE
  5891.         ErrorCode = ErrRGCBadAlgorithmFlag
  5892.     END SELECT
  5893.  
  5894. END FUNCTION
  5895. '
  5896.